In what order do angular watchers and event listeners execute?

大城市里の小女人 提交于 2019-12-22 05:23:17

问题


If one changes a scope property first, and then broadcasts an event second, will the corresponding watcher callback and event listeners callback always be executed in that same order? For example:

$scope.foo = 3;
$scope.$broadcast('bar');

and elsewhere:

$scope.$watch('foo', function fn1(){...});
$scope.$on('bar', function fn2(){...});

Will fn1 always be executed prior to fn2, or visa-versa, or can the order not be relied upon? Please cite sources, preferably to official angular docs.

In case it matters: lets assume the $scope.foo= and the $broadcast occur in a function invoked by an ng-click (i.e. user interaction)

[aside] Sorry question title is sloppy - please rename if you have something better.


回答1:


To understand what is happening, you need to understand Angular's $digest cycle and event $emit and $broadcast functions.

Based on some research, I've also learned that Angular does not use any kind of polling mechanism to periodically check for model changes. This is not explained in the Angular docs, but can be tested (see this answer to a similar question).

Putting all of that together, I wrote a simple experiment and concluded that you can rely on your event handlers running first, then your watch functions. Which makes sense, because the watch functions can be called several times in succession during the digest loop.

The following code...

template.html

<div ng-app="myApp">
  <div watch-foo ng-controller="FooController">
    <button ng-click="changeFoo()">
      Change
    </button>
  </div>
</div>

script.js

angular.module('myApp', [])
  .directive('watchFoo', watchFooDirective)
  .controller('FooController', FooController);

function watchFooDirective($rootScope) {
  return function postLink(scope) {
    scope.$watch(function () {
        return scope.foo;
    }, function (value) {
        console.log('scope.$watch A');
    });
    scope.$on('foo', function (value) {
        console.log('scope.$on A');
    });
    $rootScope.$on('foo', function (value) {
        console.log('$rootScope.$on A');
    });
    $rootScope.$on('foo', function (value) {
        console.log('$rootScope.$on B');
    });
    scope.$on('foo', function (value) {
        console.log('scope.$on B');
    });
    scope.$watch(function () {
        return scope.foo;
    }, function (value) {
        console.log('scope.$watch B');
    });
  };
}

function FooController($scope) {
  $scope.foo = 'foo';
  $scope.changeFoo = function() {
    $scope.foo = 'bar';
    $scope.$emit('foo');
  };
}

...yields the following results in the console when the 'Change' button is clicked:

scope.$on A
scope.$on B
$rootScope.$on A
$rootScope.$on B
scope.$watch A
scope.$watch B

UPDATE

Here is another test that illustrates the watch callback being called twice in the digest loop, but the event handlers not being called a second time: https://jsfiddle.net/sscovil/ucb17tLa/

And a third test that emits an event inside the watch function, then updates the value being watched: https://jsfiddle.net/sscovil/sx01zv3v/

In all cases, you can rely on the event listeners being called before the watch functions.



来源:https://stackoverflow.com/questions/34519047/in-what-order-do-angular-watchers-and-event-listeners-execute

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!