据我所知,范围观察者和过滤器都在摘要循环中重复执行。但是以下内容对我来说有点不清楚:
它们是否执行了相同数量的循环?
是否都是由相同情况触发的?
答案 0 :(得分:7)
每个摘要周期都会检查手表。 $watch
可以观看Angular expression。在表达式中,可以有一个filter Angular必须评估(使用$interpolate
)来判断监视的表达式是否已经改变。
是否都是由相同情况触发的?
因此,过滤器不是由$digest
直接运行,而是由$watch
运行。实际上,过滤器是由观察表达式的评估触发的。
有关过滤器在$digest
的性能方面特别谈到的原因有几个。看看这两个表达式:
表达式1:{{searchText+2}}
表达式2:{{searchText | myFilter:true}}
每次触发$digest
时都会评估两个表达式。因此,一个风险区域就是myFilter
可能很复杂,最终使用的处理器周期比简单的处理器周期多(如上面的+2)。
稍微不那么明显,如果过滤器不是幂等的,那么过滤器会导致所有观察者的额外运行。在$digest
的每次运行中,如果任何手表导致更改,则设置脏位。如果设置了脏位,它会再次重新运行所有手表。这允许传播任何更改。例如,如果其中一个手表更改searchText
,那么Angular需要让所有其他观察者有机会查看其结果是否取决于searchText
,因此应该更改。
这就是上面的表达式1和2之间的区别。最糟糕的情况是,myFilter
会返回一个随机数。 $digest
运行,在评估监视时看到更改(过滤器的上一个结果与新结果不匹配),因此它再次运行监视列表。由于过滤器返回一个随机数,因此结果很可能已更改,从而触发另一次$digest
次运行。等等...... Angular在通过它的观察列表进行10次循环之后有一个内置的停止 - 它表示如果结果在10次尝试之后没有稳定则出现问题,因此它会放弃投掷“错误:10 $ digest()迭代到了。中止!“
它们的执行周期是否相同?
因此每个观看的表达式(包括任何过滤器)至少每$digest
运行两次。一旦因为触发$digest
的更改而再次检查该结果是否需要传播。如果该传播导致任何更改,那么手表和过滤器将再次运行,直到没有任何变化。
当然,如果多个观察的表达式使用相同的过滤器,那么对于每个表达式,将按照上述方式运行该过滤器。