角度ng-repeat缓存(避免在状态更改时重新呈现) [英] Angular ng-repeat cache (avoid re-rendering on state change)

查看:139
本文介绍了角度ng-repeat缓存(避免在状态更改时重新呈现)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Angular应用程序中,我们使用ng-repeat渲染峰值很大. 主页显示了巨大的封面图像列表(已放置"::"和"track by"). 首次加载时可以接受.

We have huge rendering spikes with ng-repeat in Angular application. Main page shows a huge list of cover images ("::" and "track by" are in place). On first load it works acceptable.

但是,如果用户更改状态(我们使用UI-Router)并随后返回首页,则在台式机上大约需要2秒的延迟,而在移动设备上最多需要10秒的延迟.

But if user changes the state (we use UI-Router) and goes back to the home page afterwards then it is about 2s delay on desktop and up to 10 sec delay on mobile.

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

It should be instant instead: all json queries are cached. And ng-repeat already rendered that content once.

作为临时解决方案,我们使用有角ux数据网格( https://github.com/obogo/ux -angularjs-datagrid ) 它可以立即返回首页,但不能在水平模式下使用.使用专用网格仅缓存ng-repeat(或它在后台执行的任何操作)似乎有些矫kill过正.

As temporary solution we use angular ux datagrid (https://github.com/obogo/ux-angularjs-datagrid) It makes returns to front page instant, but it is not supposed to work in horizontal mode. And it seems overkill to use a dedicated grid just to cache the ng-repeat (or what ever it does behind the scene).

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

so the question follows: how is it possible to avoid ng-repeat re-render content on state change?

推荐答案

好吧,如果您禁用ng-repeat所在的作用域的作用域.然后它将不再渲染.它本质上成为静态内容.这使您可以实际控制何时渲染.

Well if you disable the scope of the scope that the ng-repeat is on. Then it will no longer render. It essentially becomes static content. This allows you to actually control when it is rendered.

ux-datagrid实际上使用此概念来关闭看不见的dom,因此angular对此一无所知,也无法渲染它.然后将其挂接到视图中.

ux-datagrid actually uses this concept to turn off dom that is out of view so angular doesn't know about it and cannot render it. Then it hooks it back up when it is in view.

每个示波器都在摘要周期内工作.在摘要周期中,它处理范围内的$ watchers.

Each scope works on a digest cycle. In the digest cycle it processes the $watchers that are on the scope.

如果您删除了这些观察者,它不会消化它或它的孩子.

If you remove those watchers, it does not digest it or it's children.

这是ux-datagrid在其代码中用于激活和停用作用域的2种方法.您可以将它们复制到另一个对象,然后将它们用于同一件事.

These are the 2 methods that the ux-datagrid uses in it's code to activate and deactivate scopes. You could copy these to another object and use them for the same thing.

/**
 * ###<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.如果视图被重新创建并且没有被缓存,那么它仍将在编译时重新渲染所有视图.但是,如果不这样做,那么不仅禁用一次监视,而且在禁用此作用域时,它也会禁用该作用域的所有子级.从本质上将其与摘要以及所有子节点分离.

I am not sure this will fully answer your question because you are using UI-Router. If the view is recreated and not cached then it will still re-render it all in the compile. However, if not this does not just do a watch once, when you disable this scope, it disables all children of that scope as well. Essentially detaching it from the digest and all child nodes with it.

重新启用它会将它们全部重新加入.因此,您只需一次停用即可真正关闭ng-repeat及其中的所有功能.直到您重新启用它,它一直都是静态的.

Re-enabling it adds them all back in. So you really turn off the ng-repeat and everything in it with one call to deactivate. It becomes static all of the way down until you re-enable it.

这篇关于角度ng-repeat缓存(避免在状态更改时重新呈现)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆