Javascript 角度ng重复缓存(避免在状态更改时重新渲染)

Javascript 角度ng重复缓存(避免在状态更改时重新渲染),javascript,angularjs,performance,caching,angularjs-ng-repeat,Javascript,Angularjs,Performance,Caching,Angularjs Ng Repeat,我们在角度应用程序中使用ng repeat有巨大的渲染峰值。 主页上显示了一个巨大的封面图片列表(“::”和“跟踪方式”已就位)。 第一次加载时,其工作正常 但如果用户改变状态(我们使用UI路由器),然后返回主页,则桌面上的延迟约为2秒,移动设备上的延迟可达10秒 它应该是即时的:所有json查询都被缓存。而ng repeat已经呈现了该内容一次 作为临时解决方案,我们使用angular ux datagrid() 它可以立即返回首页,但不应该在水平模式下工作。使用专用网格缓存ng repeat

我们在角度应用程序中使用ng repeat有巨大的渲染峰值。 主页上显示了一个巨大的封面图片列表(“::”和“跟踪方式”已就位)。 第一次加载时,其工作正常

但如果用户改变状态(我们使用UI路由器),然后返回主页,则桌面上的延迟约为2秒,移动设备上的延迟可达10秒

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

作为临时解决方案,我们使用angular ux datagrid() 它可以立即返回首页,但不应该在水平模式下工作。使用专用网格缓存ng repeat(或它在幕后所做的任何事情)似乎有点过头了


因此,问题如下:如何避免ng repeat在状态更改时重新呈现内容?

如果禁用ng repeat所在范围的范围,则可以。然后它将不再渲染。它本质上变成了静态内容。这允许您实际控制渲染的时间

ux datagrid实际上使用这个概念来关闭看不见的dom,因此angular不知道它,也无法渲染它。然后当它在视野中时,它会把它挂起来

每个作用域在一个摘要周期上工作。在摘要循环中,它处理作用域上的$watcher

如果你移除这些观察者,它就不会消化它或者它的孩子

ux数据网格在其代码中使用这两种方法来激活和停用作用域。您可以将这些复制到另一个对象,并将它们用于相同的用途

/**
 * ###<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.
}
/**
*####停用示波器###
*datagrid性能的核心特性之一是只生成作用域的能力
*要渲染的视图。这将通过删除作用域的$$监视程序来停用作用域
*习惯于知道它需要消化。从而使行失活。我们还将从中删除所有观察者
*子作用域递归地将它们存储在单独变量中的每个子级上,以便以后激活。
*它们需要重新激活,然后才能被销毁,以便进行适当的清理。
*$$childHead和$$nextSibling变量也会为angular更新,以便它甚至不会迭代
*在停用的作用域上。它完全隐藏在摘要中。
*@param{Scope}s
*@param{number}索引
*@returns{boolean}
*/
功能停用作用域(s,索引){
//如果尚未创建作用域,请跳过。
如果(&&!isActive)){//请不要停用已停用的。
s、 $emit(导出.datagrid.events.ON\u行前\u停用);
s、 $$$观察者=s.$$观察者;
s、 $$watchers=[];
s、 $$$listenerCount=s.$$listenerCount;
s、 $$listenerCount=angular.copy(s.$$$listenerCount);
减去事件(s,s$$$listenerCount);
如果(索引>=0){
s、 $$nextSibling=null;
s、 $$prevSibling=null;
}
返回true;
}
返回false;
}
/**
*####激活示波器###
*使用停用的作用域时,它确实拥有的观察程序现在存储在$$$watchers和
*可以放回$$watchers,以便angular在摘要上获取此范围。这是递归完成的
*虽然子作用域也可以激活它们。它还更新链接$$childHead和$$nextSiblings
*以完全确保作用域与停用前一样。
*@param{Scope}s
*@param{number}索引
*@returns{boolean}
*/
功能激活示波器(s,索引){
如果(s&&s$$$观察者){//不要激活已经激活的观察者。
s、 $$watchers=s.$$$watchers;
删除s.$$$观察者;
添加事件(s,s.$$$listenerCount);
删除s.$$$listenerCount;
如果(索引>=0){
s、 $$nextSibling=scopes[index+1];
s、 $$prevSibling=作用域[索引-1];
s、 $parent=范围;
}
s、 $emit(exports.datagrid.events.ON在第行激活之后);
返回true;
}
return!!(s&!s.$$$watchers);//它是否处于活动状态。
}
我不确定这是否能完全回答您的问题,因为您正在使用UI路由器。如果视图被重新创建而不是缓存,那么它仍然会在编译中重新呈现所有视图。然而,如果不是这样的话,这不仅仅是监视一次,当您禁用这个作用域时,它也会禁用该作用域的所有子项。本质上是将其与摘要和所有子节点分离


重新启用它会将它们全部添加回。因此,您只需一次呼叫即可关闭ng repeat和其中的所有功能。它会一直保持静态,直到您重新启用它。

使用缓存什么的共享服务?所有Json都使用$cacheFactory进行缓存。问题在于渲染。您是否在服务器上压缩图像?它们有多大?您是否使用css调整它们的大小?您可以缓存您认为需要缓存的任何内容。老实说,这听起来像是一个和图像有关的东西,如果你能做一把小提琴或其他东西来摆弄它,那就太酷了。如果页面根本不需要重新呈现,您可以使用一个指令缓存dom。在深入挖掘Angular UI Router后,我发现:这正是我面临的问题。Wes解决方案是好的,如果我只渲染几个封面,禁用范围,然后启用它。