$q defer and promises and how to use them to load

2019-02-19 20:23发布

问题:

This has been the most relevant thing I found: https://stackoverflow.com/a/11972028/110233

It seems to work fine when I only want to return one thing, but I'm unsure on how to return multiple things when the other things depend on the first thing.

Since that's kind of obtuse, here's a small example on what I'm currently doing:

window.EventRosterCtrl = ($scope, subevent) ->
    $scope.subevent = subevent

EventRosterCtrl.resolve = 
    subevent: (SubEvent, $route) ->
        deferred = $q.defer()

        SubEvent.get {subevent_id: $route.current.pathParams.subevent_id}, (subevent) ->
            deferred.resolve subevent

        return deferred.promise

And here's an example of what I would want to do:

window.EventRosterCtrl = ($scope, subevent, addresses) ->
    $scope.subevent = subevent
    $scope.addresses = addresses

EventRosterCtrl.resolve = 
    subevent: (SubEvent, $route) ->
        deferred = $q.defer()

        SubEvent.get {subevent_id: $route.current.pathParams.subevent_id}, (subevent) ->
            deferred.resolve subevent

        return deferred.promise

    addresses: (User) ->
        deferred = $q.defer()

        # how do you get subevent called first and how would you access it here?
        for participant in subevent.participants
            User.get {user_id: participant.user}, (user) ->
                addresses[participant._id] = user.address

        deferred.resolve addresses

        return deferred.promise

回答1:

you need to chain promisses using the .then()

  var promise = firstOperation();
  promise = promise.then(function(value) {
    // do some more work
    return value; // it can be another promise
  });
  return promise; // this one will be resolved when both steps are resolved


回答2:

Ok, so a you can't control it that way, but a work around that comes to mind (when one resolution is dependent on another finishing first) is just put everything in one object and resolve that. What ended up working best for me was making a service, but to follow my original example:

window.EventRosterCtrl = ($scope, info) ->
    $scope.subevent = info.subevent
    $scope.addresses = info.addresses

EventRosterCtrl.resolve = 
    info: (SubEvent, User, $route, $q) ->
        deferred = $q.defer()
        resolvedInfo = {}

        SubEvent.get {subevent_id: $route.current.pathParams.subevent_id}, (subevent) ->
            resolvedInfo.subevent = subevent

            for participant in subevent.participants
                User.get {user_id: participant.user}, (user) ->
                    addresses[participant._id] = user.address

                    if addresses.length is subevent.participants.length
                        resolvedInfo.addresses = addresses
                        deferred.resolve resolvedInfo

        return deferred.promise


回答3:

The EventRosterCtrl is only initialized when the subevent is ready, so the following should work:

window.EventRosterCtrl = ($scope, subevent) ->
    $scope.subevent = subevent

    for participant in subevent.participants
        User.get {user_id: participant.user}, (user) ->
            $scope.addresses[participant._id] = user.address

EventRosterCtrl.resolve = 
    subevent: (SubEvent, $route) ->
        deferred = $q.defer()

        SubEvent.get {subevent_id: $route.current.pathParams.subevent_id}, (subevent) ->
            deferred.resolve subevent

        return deferred.promise