一个指令=一个额外的观察者?

时间:2014-12-18 19:18:32

标签: angularjs

每个指令都有一个额外的观察者吗? 以下是示例代码 - http://plnkr.co/edit/Mg4Z7PUUJI0dQRNfFZ8z?p=preview 它有4个自定义指令和一次性绑定,但我有5个观察者,应该只有1个。 为什么呢?



 angular.module("myApp", [])
            .controller("initCtrl", function ($scope, $interval) {
                $scope.dane = {
                    zm1: 'Directive 1 with onetime binding',
                    zm2: 'Directive 2 with onetime binding',
                    zm3: 'Directive 3 with onetime binding',
                    zm4: 'Directive 4 with onetime binding',
                };

                $interval(function () {
                    $scope.watchers = countWatchers();
                }, 1000);
            })
            .directive("myDir", function () {
                return {
                    scope: {
                        ngModel: "="
                    },
                    require: "ngModel",
                    link: function (scope, element, attrs, ctrl) {

                    },
                    template: "<div>{{::ngModel}}</div>"
                }
            })
    ;
    /**
     * Funkcja do zliczania watchers - max 2000
     */
    (function () {
        window.countWatchers = function () {
            var root = angular.element(document.getElementsByTagName('body'));

            var watchers = [];

            var f = function (element) {
                angular.forEach(['$scope', '$isolateScope'], function (scopeProperty) {
                    if (element.data() && element.data().hasOwnProperty(scopeProperty)) {
                        angular.forEach(element.data()[scopeProperty].$$watchers, function (watcher) {
                            watchers.push(watcher);
                        });
                    }
                });

                angular.forEach(element.children(), function (childElement) {
                    f(angular.element(childElement));
                });
            };

            f(root);

            // Remove duplicate watchers
            var watchersWithoutDuplicates = [];
            angular.forEach(watchers, function (item) {
                if (watchersWithoutDuplicates.indexOf(item) < 0) {
                    watchersWithoutDuplicates.push(item);
                }
            });
            return watchersWithoutDuplicates.length;
        };
    })();
&#13;
<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@1.3.6" data-semver="1.3.6" src="https://code.angularjs.org/1.3.6/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body data-ng-app="myApp">
<div ng-controller="initCtrl" class="container">
    <div class="well">Watchers: {{watchers}}</div>
    <my-dir ng-model="::dane.zm1"></my-dir>
    <my-dir ng-model="::dane.zm2"></my-dir>
    <my-dir ng-model="::dane.zm3"></my-dir>
    <my-dir ng-model="::dane.zm4"></my-dir>
</div>
  </body>

</html>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:2)

我明白了。使用ng-model指令(作为属性)会增加额外的观察者。

结论:如果您不需要双向绑定或需要真正的一次绑定,请不要将ng-model用作属性。

angular.module("myApp", [])
            .controller("initCtrl", function ($scope, $interval) {
                $scope.dane = {
                    zm1: 'Directive 1 with onetime binding',
                    zm2: 'Directive 2 with onetime binding',
                    zm3: 'Directive 3 with onetime binding',
                    zm4: 'Directive 4 with onetime binding'
                };
                $scope.change = function () {
                    $scope.dane.zm1 = "Changed";
                };

                $interval(function () {
                    $scope.watchers = countWatchers();
                }, 1000);
            })
            .directive("myDir", function () {
                return {
                    scope: {
                        ngModel: "="
                    },
                    require: "ngModel",
                    link: function (scope, element, attrs, ctrl) {

                    },
                    template: "<div>{{::ngModel}} - extra watcher due to ngModel</div>"
                }
            })
            .directive("myDirNgModel", function () {
                return {
                    scope: {
                        ngModel: "="
                    },
                    require: "ngModel",
                    link: function (scope, element, attrs, ctrl) {

                    },
                    template: "<div>{{ngModel}} - three extra watcher - ngModel, declaration, directive</div>"
                }
            })
            .directive("ngBindOneWay", function () {
                return {
                    scope: {
                        var: "@"
                    },
                    link: function (scope, element, attrs, ctrl) {

                    },
                    template: "<div>{{::var}} - no extra watchers</div>"
                }
            })
            .directive("ngBindTwoWayOneTime", function () {
                return {
                    scope: {
                        var: "="
                    },
                    link: function (scope, element, attrs, ctrl) {

                    },
                    template: "<div>{{::var}} - no extra watchers</div>"
                }
            })
            .directive("ngBindTwoWay", function () {
                return {
                    scope: {
                        var: "="
                    },
                    link: function (scope, element, attrs, ctrl) {

                    },
                    template: "<div>{{var}} - two extra watchers - declaration and directive</div>"
                }
            })
            .directive("myDirNoBind", function () {
                return {
                    scope: {},
                    link: function (scope, element, attrs) {

                    },
                    template: "<div>No bindings - no extra watchers</div>"
                }
            })
    ;
    /**
     * Funkcja do zliczania watchers - max 2000
     */
    (function () {
        window.countWatchers = function () {
            var root = angular.element(document.getElementsByTagName('body'));

            var watchers = [];

            var f = function (element) {
                angular.forEach(['$scope', '$isolateScope'], function (scopeProperty) {
                    if (element.data() && element.data().hasOwnProperty(scopeProperty)) {
                        angular.forEach(element.data()[scopeProperty].$$watchers, function (watcher) {
                            watchers.push(watcher);
                        });
                    }
                });

                angular.forEach(element.children(), function (childElement) {
                    f(angular.element(childElement));
                });
            };

            f(root);

            // Remove duplicate watchers
            var watchersWithoutDuplicates = [];
            angular.forEach(watchers, function (item) {
                if (watchersWithoutDuplicates.indexOf(item) < 0) {
                    watchersWithoutDuplicates.push(item);
                }
            });
            return watchersWithoutDuplicates.length;
        };
    })();
<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@1.3.6" data-semver="1.3.6" src="https://code.angularjs.org/1.3.6/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body data-ng-app="myApp">
<div ng-controller="initCtrl" class="container">
    <div class="well">Watchers: {{watchers}} - first watcher</div>
    <my-dir ng-model="::dane.zm1"></my-dir>
    <my-dir-ng-model ng-model="dane.zm1"></my-dir-ng-model>
    <my-dir-no-bind></my-dir-no-bind>
    <ng-bind-one-way var="{{::dane.zm1}}"></ng-bind-one-way>
    <ng-bind-two-way var="dane.zm1"></ng-bind-two-way>
    <ng-bind-two-way-one-time var="::dane.zm1"></ng-bind-two-way-one-time>
    <div><a ng-click="change()" href="javascript:void(null)">Change zm1</a></div>
</div>
  </body>

</html>