角度消化循环的高级增强

时间:2017-05-23 07:59:27

标签: angularjs

我正在研究增强角度消化循环的选项。

我有一个相当复杂的应用程序,在任何给定时间都有成千上万的活跃观察者。

作为app的功能的一部分,我正在注册滚动事件(并在动画帧中处理它们),因此摘要基本上在每个滚动上执行,这导致fps偶尔下降。

我通过一次性绑定减少了观察者数量,现在我只剩下几千名观察者。

目前我正在尝试编写一个指令来暂停视口元素之外的所有观察者。

所以我开始玩角形内部并提出以下指令:

app.directive('ngSuspendable', function () {
    return {
        restrict: 'A',
        scope: true,
        link: function (scope, element, attr) {
            var _watchersMap = {};
            var _suspended = true;
            suspendWatchersTree();

            function suspendWatchersTreeRecursive(currentScope, includeSiblings) {
                while (currentScope != null) {
                    if ((currentScope.$$watchers != null) &&
                        (currentScope.$$watchers.length > 0) &&
                        (typeof _watchersMap[currentScope.$id] == "undefined")) {
                        _watchersMap[currentScope.$id] = currentScope.$$watchers;
                        currentScope.$$watchers = [];
                    }

                    if (currentScope.$$childHead != null) {
                        suspendWatchersTreeRecursive(currentScope.$$childHead, true);
                    }

                    if (includeSiblings) {
                        currentScope = currentScope.$$nextSibling;
                    }

                    else {
                        currentScope = null;
                    }
                }
            }

            function unsuspendWatchersTreeRecursive(currentScope, includeSiblings) {
                while (currentScope != null) {
                    if ((typeof _watchersMap[currentScope.$id] != "undefined") &&
                        (_watchersMap[currentScope.$id].length > 0)) {
                        if ((currentScope.$$watchers != null) &&
                            (currentScope.$$watchers.length > 0)) {
                            currentScope.$$watchers = currentScope.$$watchers.concat(_watchersMap[currentScope.$id]);
                        }

                        else {
                            currentScope.$$watchers = _watchersMap[currentScope.$id];
                        }
                    }

                    if (currentScope.$$childHead != null) {
                        unsuspendWatchersTreeRecursive(currentScope.$$childHead, true);
                    }

                    if (includeSiblings) {
                        currentScope = currentScope.$$nextSibling;
                    }

                    else {
                        currentScope = null;
                    }
                }
            }

            function suspendWatchersTree() {
                suspendWatchersTreeRecursive(scope, false);
            }

            function unsuspendWatchersTree() {
                unsuspendWatchersTreeRecursive(scope, false);
            }

            scope.inView = function(evnt, model, htmlElementId, triggeringEvent, isInView, inViewPart) {
                if (!isInView) {
                    suspendWatchersTree();
                    _suspended = true;
                }

                if ((isInView) && (_suspended)) {
                    unsuspendWatchersTree();
                    _watchersMap = {};
                    _suspended = false;
                }
            }
        }
    }
});

初始化时,该指令从当前作用域和所有子作用域中删除所有观察者(不确定它是否也捕获了孤立的作用域)。 然后,当元素在视图中时,它会添加回观察者,并在视野之外将其删除。

我知道它并不一定会捕获所有观察者,因为一些观察者可能会在链接后添加,但这似乎可以忽略不计,并且一旦元素进入视图并再次出现,它们将被删除。如果我可以以某种方式挂钩观察者的添加并将其添加到地图上,当被怀疑可能很好但我想它不是必须的。

这似乎运作良好,但我不确定这种方法的注意事项。我喜欢玩角形内部和弄乱东西并达到不稳定的条件。

非常感谢任何想法和评论。

1 个答案:

答案 0 :(得分:0)

我已使用最新更改更新了上述代码。 进一步测试显示它运行良好,一些手表可能不会在初始化时暂停,但这是我可以忍受的价格。它大大增强了我的摘要循环,并通过删除视口元素之外的不需要的手表来提升应用程序性能。