javascript AngularJS 摘要循环多久运行一次?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25177704/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 04:07:32  来源:igfitidea点击:

How often does the AngularJS digest loop run?

javascriptangularjsjavascript-eventsevent-handling

提问by derekchen14

When discussing the merits of AngularJS, two-way data binding is often touted as a major benefit of Angular over other JS frameworks. Digging deeper, the documentation suggests this process is done through dirty-checking rather than through event-driven measures. At first, it seems that the digest-loop works by having a method fire off in the background at periodic intervals, checking all the $watches during each cycle. However, reading further, it seems that the digest-loop is actually triggered by rootScope.digest(), which in turn is triggered by $.apply, which is in turn triggered by an event(!), such as an onClick event called through ng-click.

在讨论 AngularJS 的优点时,双向数据绑定通常被吹捧为 Angular 优于其他 JS 框架的主要优点。 深入挖掘,文档表明这个过程是通过脏检查而不是通过事件驱动的措施来完成的。起初,digest-loop 似乎是通过在后台定期触发一个方法来工作的,$watch在每个循环中检查所有es。但是,进一步阅读,似乎摘要循环实际上是由 触发的rootScope.digest(),而 又由 触发$.apply,而 又由 事件(!)触发,例如调用 through 的 onClick 事件ng-click

But, how can this be? I thought Angular doesn't use change listeners. So how does the digest-loop really operate? Does Angular automatically kick-off the digest-loop internally, or is the digest-loop triggered by events?If the digest-loop is run automatically, how often does it run?

但是,这怎么可能?我认为 Angular不使用更改侦听器。那么digest-loop究竟是如何运作的呢? Angular 是在内部自动启动摘要循环,还是由事件触发摘要循环?如果digest-loop 自动运行,它多久运行一次?



Some clarification points:

一些澄清点:

  • I'm not asking about how the digest-loop runs when manually binding to changes. In this case, if you want to force a digest loop, you can do so by calling $.apply()
  • I'm also not asking about how often digest loop runs in response to user events. For example, if ng-model is on an input box, Angular will kick-off a digest loop when a user starts typing. The confusing part is that in order to know a user was typing, doesn't Angular use an event-basedonKeyUp somewhere?
  • I already know that there is a limit of 10 cycles max per digest-loop. My question is less about the number of cycles per digest-loop, but rather the number of digest-loops that run, say, per second.
  • Bonus questions: How does the digest-loop relate to the JavaScript event-loop? Does the JS event loop run periodically in the background? Is the digest-loop the same thing as the event loop, but only in the "Angular Context"? Are these totally different ideas?
  • 我不是在问在手动绑定到更改时摘要循环如何运行。在这种情况下,如果你想强制一个摘要循环,你可以通过调用$.apply()
  • 我也不是询问消化循环响应用户事件的频率。例如,如果 ng-model 在输入框上,当用户开始输入时,Angular 将启动一个摘要循环。令人困惑的部分是,为了知道用户正在打字,Angular 不是在某处使用基于事件的onKeyUp 吗?
  • 我已经知道每个摘要循环最多有 10 个周期的限制。我的问题不是关于每个摘要循环的周期数,而是关于每秒运行的摘要循环数。
  • 额外问题:摘要循环与 JavaScript 事件循环有何关联?JS 事件循环是否在后台定期运行?摘要循环是否与事件循环相同,但仅在“角度上下文”中?这些是完全不同的想法吗?

采纳答案by pixelbits

Angular digests are triggered - they don't happen through polling.

Angular 摘要被触发 - 它们不会通过轮询发生。

Code executes, after code is done, angular triggers a digest.

代码执行,代码完成后,angular 触发摘要。

Example:

例子:

 element.on('click', function() {
     $scope.$apply(function() { 
         // do some code here, after this, $digest cycle will be triggered
     });
 });

Angular will also trigger a $digest after the compile/link phase:

Angular 还会在编译/链接阶段后触发 $digest :

Compile > Link > Digest

And as to how many digest cycles are triggered? It depends on how soon the scope variables stabalise. Usually it takes at least 2 cycles to determine that.

至于触发了多少个消化周期?这取决于范围变量多久稳定下来。通常至少需要 2 个周期才能确定。

回答by Roger Jin

Short direct answer to the main question is "NO", angular doesn't automatically trigger digest loop.

主要问题的简短直接回答是“否”,angular 不会自动触发摘要循环。

TL;DR answer:

TL;博士回答:

Digest loop is designed to run dirty check over POJO models associated with Angular scope instances, so it only needs to run when a model might be changed. In a single page Web application running inside Browser, the following actions/events could lead to a model change

摘要循环旨在对与 Angular 范围实例关联的 POJO 模型运行脏检查,因此它只需要在模型可能更改时运行。在浏览器中运行的单页 Web 应用程序中,以下操作/事件可能会导致模型更改

  1. DOM events
  2. XHR responses firing callbacks
  3. Browser's location changes
  4. Timers (setTimout, setInterval) firing the callbacks
  1. DOM 事件
  2. XHR 响应触发回调
  3. 浏览器位置变化
  4. 定时器(setTimout,setInterval)触发回调

Correspondingly, Angular trigger digest loop at, for instance

相应地,例如在 Angular 触发摘要循环

  1. input directives+ngModel, ngClick, ngMouseOver etc.
  2. $http and $resource
  3. $location
  4. $timeout
  1. 输入指令+ngModel、ngClick、ngMouseOver 等。
  2. $http 和 $resource
  3. $location
  4. $超时

Try to answer those bonus questions from my understanding:

尝试根据我的理解回答这些奖励问题:

  1. ngModel directive often used with angular input directives (text, select etc) together, and the laters will listen on "change" events and call $setViewValue API exposed from ngModelController in order to sync back dom value. During the sync process, ngModelController will make sure to trigger digest loop.
  2. digest loop is different from JS event loop, the later is concept of JS runtime (checkout the great visualised session https://www.youtube.com/watch?v=8aGhZQkoFbQ) which run against event queue and remove consumed event from the queue automatically, but digest loop never remove watch from its watch list unless you explicitly unwatch.
  3. the number of digest loops per second depends on the efficiency of all watch callbacks being executed through the loop . If some bad code took one second to finish, then this digest loop would cost more than 1 sec.
  1. ngModel 指令通常与角度输入指令(文本、选择等)一起使用,后者将侦听“更改”事件并调用从 ngModelController 公开的 $setViewValue API 以同步回 dom 值。在同步过程中,ngModelController 会确保触发摘要循环。
  2. 摘要循环不同于 JS 事件循环,后者是 JS 运行时的概念(查看伟大的可视化会话 https://www.youtube.com/watch?v=8aGhZQkoFbQ),它针对事件队列运行并从队列中删除消耗的事件自动,但摘要循环永远不会从其监视列表中删除监视,除非您明确取消监视。
  3. 每秒摘要循环的数量取决于通过循环执行的所有观察回调的效率。如果一些糟糕的代码需要一秒钟才能完成,那么这个摘要循环将花费超过 1 秒钟。

So some key practices for avoid angular performance pitfalls are

因此,避免角度性能陷阱的一些关键实践是

  1. Watch callback should be coded as simpler/efficient as possible, for example detach complicated algorithm code to, for example, worker threads
  2. Proactively remove a watch if it is not used anymore
  3. Prefer to call $scope.$digest() instead of $scope.$apply() if applicable, $digest() only run part of scope tree and ensure the models associated under the subtree is reflecting to view. But $apply() will run against entire scope tree, it will iterate through more watches.
  1. 监视回调应该尽可能简单/高效地编码,例如将复杂的算法代码分离到工作线程
  2. 如果不再使用,请主动移除手表
  3. 如果适用,最好调用 $scope.$digest() 而不是 $scope.$apply(),$digest() 只运行范围树的一部分,并确保子树下关联的模型反映到视图中。但是 $apply() 将针对整个范围树运行,它将遍历更多的手表。

回答by Chandermani

I believe this is what happens. AngularJS made a smart assumption that model changes happen only on user interaction. These interactions can happen due to

我相信这就是发生的事情。AngularJS 做出了一个聪明的假设,即模型更改仅在用户交互时发生。这些相互作用可能是由于

  • Mouse activity (move, clicked etc)
  • Keyboard activity (key up, key down etc)
  • 鼠标活动(移动、点击等)
  • 键盘活动(向上键、向下键等)

AngularJS directives for the corresponding events wrap the expression execution in $scope.$apply as shown by @pixelbits in his example. This results in digest cycle.

相应事件的 AngularJS 指令将表达式执行包装在 $scope.$apply 中,如他的示例中的@pixelbits 所示。这导致消化循环。

There are some other events too where AngularJS triggers the digest loop. $timeout service and the $interval service are two such examples. Code wrapped in these service also results in digest loop to run. There maybe be some other events\services that can cause digest cycles to execute but these are the major ones.

还有一些其他事件是 AngularJS 触发摘要循环的地方。$timeout 服务和 $interval 服务就是两个这样的例子。封装在这些服务中的代码也会导致运行摘要循环。可能还有一些其他事件\服务会导致摘要循环执行,但这些是主要的。

This is the very reason that changes to model outside the Angular context does not update the watches and bindings. So one needs to explicitly call $scope.$apply. We do it all the time when integrating with jQuery plugins.

这就是在 Angular 上下文之外更改模型不会更新监视和绑定的原因。所以需要显式调用 $scope.$apply。我们在与 jQuery 插件集成时一直这样做。