AngularJS : $q -> deferred API order of things (lifecycle) AND who invokes digest?

后端 未结 2 832
南旧
南旧 2020-11-27 19:06

The $q service is very powerful in angularjs and make our life easier with asynchronous code.

I am new to angular but using deferred API is not very new to me. I mu

2条回答
  •  死守一世寂寞
    2020-11-27 19:52

    when the promise resolves - it invokes the digest loop ?

    Yes. You can test this by a simple template:

    {{state}}
    

    and controller code that changes the $scope.state variable after a delay:

    $scope.state = 'Pending';
    var d = $q.defer();
    d.promise.then(function() {
      $scope.state = 'Resolved, and digest cycle must have run';
    });
    $window.setTimeout(function() {
      d.resolve();
    }, 1000);
    

    You can see this at http://plnkr.co/edit/fIfHYz9EYK14A5OS6NLd?p=preview. After a second, the text in the HTML shows Resolved, and digest cycle must have run. The call to setTimeout rather than $timeout is deliberate, to ensure that it must be resolve which ends up starting the digest loop.

    This is confirmed by looking in the source: resolve calls its callbacks via nextTick, which is a function that passed the callbacks to $rootScope.$evalAsync, which according to the $evalAsync docs:

    at least one $digest cycle will be performed after expression execution

    Those same docs also say:

    Note: if this function is called outside of a $digest cycle, a new $digest cycle will be scheduled

    so whether the stack is already in the $digest loop can change the exact order of events.


    '1. What is the order of things that happen in each of your described steps / phases

    Going into the previous example in detail:

    1. var d = $q.defer(); The deferred object's promise is in a pending state. At this point, virtually nothing has happened, you just have a deferred object with resolve, reject, notifiy and promise properties. Nothing has used or affected the $digest loop

    2. d.promise.then(function() { $scope.state = 'Resolved, and digest cycle must have run'; });

      The promise is still in a pending state, but with a then success callback registered. Again, nothing has used or affected the $digest loop or any scope.

    3. $window.setTimeout(function() { d.resolve(); }, 1000);

      After 1 second, d.resolve will be called. This passes the callback defined in Step 2 above to $evalAsync (via nextTick).

    4. $evalAsync will call the callback

    5. $evalAsync will then ensure one $digest cycle will be called.


    '2. When new deferred object with a new promise instance created - who aware of it / is it important ?

    Only the caller of $q.defer(). Nothing happens with respect to any scope until resolved is called (or indeed, reject or notify).


    '3. How exactly the scope updated promise object being resolved? Do i have to update it manually inside the callback or the digest will be automatically invoked and update the rootScope like declared here

    As mentioned, the $digest loop will be automatically started by calling resolve (if it's not in it already).


    '4. mention at least one approach of updating the scope from within the promise callback

    The example above gives this.


    '5. I assume there a lot of other useful aspects, feel free to provide them all.

    Not that I can think of!

提交回复
热议问题