Angular ng-repeat缓存(避免在状态更改时重新呈现)

时间:2015-06-22 17:48:06

标签: javascript angularjs performance caching angularjs-ng-repeat

我们在Angular应用程序中使用ng-repeat有很大的渲染峰值。 主页显示了大量的封面图像(“::”和“跟踪”已经到位)。 首次加载时,它可以接受。

但是如果用户更改了状态(我们使用UI-Router)并且之后返回主页,则桌面上的延迟大约为2秒,移动终端则延迟大约10秒。

它应该是即时的:所有json查询都被缓存。并且ng-repeat已经将该内容呈现一次。

作为临时解决方案,我们使用angular ux datagrid(https://github.com/obogo/ux-angularjs-datagrid) 它会立即返回首页,但它不应该在水平模式下工作。使用专用网格来缓存ng-repeat(或者它在场景后面做的事情)似乎有点过分了。

所以问题如下:如何避免ng-repeat重新呈现状态变化内容?

1 个答案:

答案 0 :(得分:2)

如果你禁用了ng-repeat所在的范围,那就好了。然后它将不再呈现。它本质上成为静态内容。这允许您实际控制何时渲染。

ux-datagrid实际上使用这个概念来关闭不在视野范围内的dom,因此角度不知道它并且无法渲染它。然后它在视野中将其挂起。

每个范围都适用于摘要周期。在摘要周期中,它处理范围内的$观察者。

如果你删除那些观察者,它就不会消化它或它的孩子。

这些是ux-datagrid在其代码中用于激活和停用作用域的两种方法。你可以将它们复制到另一个对象并使用它们来做同样的事情。

/**
 * ###<a name="deactivateScope">deactivateScope</a>###
 * One of the core features to the datagrid's performance is the ability to make only the scopes
 * that are in view to render. This deactivates a scope by removing its $$watchers that angular
 * uses to know that it needs to digest. Thus inactivating the row. We also remove all watchers from
 * child scopes recursively storing them on each child in a separate variable to activate later.
 * They need to be reactivated before being destroyed for proper cleanup.
 * $$childHead and $$nextSibling variables are also updated for angular so that it will not even iterate
 * over a scope that is deactivated. It becomes completely hidden from the digest.
 * @param {Scope} s
 * @param {number} index
 * @returns {boolean}
 */
function deactivateScope(s, index) {
    // if the scope is not created yet. just skip.
    if (s && !isActive(s)) { // do not deactivate one that is already deactivated.
        s.$emit(exports.datagrid.events.ON_BEFORE_ROW_DEACTIVATE);
        s.$$$watchers = s.$$watchers;
        s.$$watchers = [];
        s.$$$listenerCount = s.$$listenerCount;
        s.$$listenerCount = angular.copy(s.$$$listenerCount);
        subtractEvents(s, s.$$$listenerCount);
        if (index >= 0) {
            s.$$nextSibling = null;
            s.$$prevSibling = null;
        }
        return true;
    }
    return false;
}

/**
 * ###<a name="activateScope">activateScope</a>###
 * Taking a scope that is deactivated the watchers that it did have are now stored on $$$watchers and
 * can be put back to $$watchers so angular will pick up this scope on a digest. This is done recursively
 * though child scopes as well to activate them. It also updates the linking $$childHead and $$nextSiblings
 * to fully make sure the scope is as if it was before it was deactivated.
 * @param {Scope} s
 * @param {number} index
 * @returns {boolean}
 */
function activateScope(s, index) {
    if (s && s.$$$watchers) { // do not activate one that is already active.
        s.$$watchers = s.$$$watchers;
        delete s.$$$watchers;
        addEvents(s, s.$$$listenerCount);
        delete s.$$$listenerCount;
        if (index >= 0) {
            s.$$nextSibling = scopes[index + 1];
            s.$$prevSibling = scopes[index - 1];
            s.$parent = scope;
        }
        s.$emit(exports.datagrid.events.ON_AFTER_ROW_ACTIVATE);
        return true;
    }
    return !!(s && !s.$$$watchers); // if it is active or not.
}

我不确定这会完全回答您的问题,因为您使用的是UI-Router。如果视图被重新创建而不是缓存,那么它仍然会在编译中重新渲染它。但是,如果不是,这不仅仅是一次监视,当您禁用此范围时,它也会禁用该范围的所有子项。基本上将它与摘要和所有子节点分离。

重新启用它会将它们全部添加回来。所以你真的关闭ng-repeat及其中的所有内容,只需一次调用即可停用。它会一直静止,直到你重新启用它。