I don't understand how to use $scope.$watch
and $scope.$apply
. The official documentation isn't helpful.
我不知道如何使用$scope。观察和适用范围。美元美元。官方文件没有帮助。
What I don't understand specifically:
我不太明白的是:
- Are they connected to the DOM?
- 它们是否连接到DOM?
- How can I update DOM changes to the model?
- 如何更新模型的DOM更改?
- What is the connection point between them?
- 它们之间的连接点是什么?
I tried this tutorial, but it takes the understanding of $watch
and $apply
for granted.
我尝试了本教程,但是它认为对$watch和$apply的理解是理所当然的。
What do $apply
and $watch
do, and how do I use them appropriately?
$apply和$watch有什么作用,我如何恰当地使用它们?
7 个解决方案
#1
1630
You need to be aware about how AngularJS works in order to understand it.
你需要了解AngularJS是如何工作的,才能理解它。
Digest cycle and $scope
First and foremost, AngularJS defines a concept of a so-called digest cycle. This cycle can be considered as a loop, during which AngularJS checks if there are any changes to all the variables watched by all the $scope
s. So if you have $scope.myVar
defined in your controller and this variable was marked for being watched, then you are implicitly telling AngularJS to monitor the changes on myVar
in each iteration of the loop.
首先也是最重要的是,AngularJS定义了所谓的消化循环的概念。这个循环可以看作一个循环,在这个循环中,AngularJS检查所有$作用域监视的所有变量是否有任何更改。如果你有$scope。在控制器中定义的myVar,这个变量被标记为被监视,然后隐式地告诉AngularJS在循环的每次迭代中监视myVar上的变化。
A natural follow-up question would be: Is everything attached to $scope
being watched? Fortunately, no. If you would watch for changes to every object in your $scope
, then quickly a digest loop would take ages to evaluate and you would quickly run into performance issues. That is why the AngularJS team gave us two ways of declaring some $scope
variable as being watched (read below).
一个自然的后续问题是:所有与$scope相关的东西都在被监视吗?幸运的是,没有。如果您要监视对$范围内的每个对象的更改,那么很快就会需要很长时间来评估一个摘要循环,您将很快遇到性能问题。这就是为什么AngularJS团队给了我们两种方法来声明某个$scope变量作为监视对象(请参阅下面的内容)。
$watch helps to listen for $scope changes
There are two ways of declaring a $scope
variable as being watched.
有两种方法可以声明要监视的$scope变量。
- By using it in your template via the expression
<span>{{myVar}}</span>
- 通过在模板中通过表达式{{myVar} 使用它
- By adding it manually via the
$watch
service - 通过$watch服务手动添加它。
Ad 1) This is the most common scenario and I'm sure you've seen it before, but you didn't know that this has created a watch in the background. Yes, it had! Using AngularJS directives (such as ng-repeat
) can also create implicit watches.
Ad 1)这是最常见的场景,我敢肯定你以前见过,但你不知道它在后台创建了一个手表。是的,它有!使用AngularJS指令(例如ng-repeat)也可以创建隐式表。
Ad 2) This is how you create your own watches. $watch
service helps you to run some code when some value attached to the $scope
has changed. It is rarely used, but sometimes is helpful. For instance, if you want to run some code each time 'myVar' changes, you could do the following:
这就是你如何创建自己的手表。$watch服务帮助您运行一些代码,当附加到$scope的值发生变化时。它很少被使用,但有时是有用的。例如,如果您希望在每次“myVar”更改时运行一些代码,您可以执行以下操作:
function MyController($scope) {
$scope.myVar = 1;
$scope.$watch('myVar', function() {
alert('hey, myVar has changed!');
});
$scope.buttonClicked = function() {
$scope.myVar = 2; // This will trigger $watch expression to kick in
};
}
$apply enables to integrate changes with the digest cycle
You can think of the $apply
function as of an integration mechanism. You see, each time you change some watched variable attached to the $scope
object directly, AngularJS will know that the change has happened. This is because AngularJS already knew to monitor those changes. So if it happens in code managed by the framework, the digest cycle will carry on.
您可以将$apply函数看作是一种集成机制。您可以看到,每当您更改一个直接连接到$scope对象的受监视变量时,AngularJS将知道所发生的更改。这是因为AngularJS已经知道要监控这些变化。因此,如果它发生在由框架管理的代码中,那么摘要循环将继续下去。
However, sometimes you want to change some value outside of the AngularJS world and see the changes propagate normally. Consider this - you have a $scope.myVar
value which will be modified within a jQuery's $.ajax()
handler. This will happen at some point in future. AngularJS can't wait for this to happen, since it hasn't been instructed to wait on jQuery.
然而,有时您希望在AngularJS世界之外更改一些值,并看到更改正常传播。考虑到这一点——您有一个$范围。将在jQuery $.ajax()处理程序中修改的myVar值。这将在未来的某个时刻发生。AngularJS都等不及了,因为它还没有被指示要等待jQuery。
To tackle this, $apply
has been introduced. It lets you start the digestion cycle explicitly. However, you should only use this to migrate some data to AngularJS (integration with other frameworks), but never use this method combined with regular AngularJS code, as AngularJS will throw an error then.
为了解决这个问题,我们引入了$apply。它可以让你明确地开始消化循环。但是,您应该只使用此方法将一些数据迁移到AngularJS(与其他框架集成)中,但不要将此方法与常规的AngularJS代码结合使用,因为AngularJS会抛出错误。
How is all of this related to the DOM?
Well, you should really follow the tutorial again, now that you know all this. The digest cycle will make sure that the UI and the JavaScript code stay synchronised, by evaluating every watcher attached to all $scope
s as long as nothing changes. If no more changes happen in the digest loop, then it's considered to be finished.
好吧,既然你已经知道了这些,你应该再看一遍教程。摘要周期将通过评估每个附加到所有$作用域的观察者(只要不发生任何变化)来确保UI和JavaScript代码保持同步。如果在摘要循环中没有发生任何更改,则认为已完成。
You can attach objects to the $scope
object either explicitly in the Controller, or by declaring them in {{expression}}
form directly in the view.
可以在控制器中显式地将对象附加到$scope对象,也可以通过在视图中直接在{{{expression}}}窗体中声明对象。
I hope that helps to clarify some basic knowledge about all this.
我希望这有助于澄清关于这一切的一些基本知识。
Further readings:
进一步阅读:
- Make Your Own AngularJS, Part 1: Scopes And Digest
- 制作你自己的AngularJS,第1部分:作用域和摘要
#2
151
In AngularJS, we update our models, and our views/templates update the DOM "automatically" (via built-in or custom directives).
在AngularJS中,我们更新模型,我们的视图/模板“自动”更新DOM(通过内置或自定义指令)。
$apply and $watch, both being Scope methods, are not related to the DOM.
$apply和$watch都是范围方法,与DOM无关。
The Concepts page (section "Runtime") has a pretty good explanation of the $digest loop, $apply, the $evalAsync queue and the $watch list. Here's the picture that accompanies the text:
concept页面(“Runtime”部分)对$digest循环、$apply、$evalAsync队列和$watch列表有很好的解释。这是伴随文字的图片:
Whatever code has access to a scope – normally controllers and directives (their link functions and/or their controllers) – can set up a "watchExpression" that AngularJS will evaluate against that scope. This evaluation happens whenever AngularJS enters its $digest loop (in particular, the "$watch list" loop). You can watch individual scope properties, you can define a function to watch two properties together, you can watch the length of an array, etc.
任何代码都可以访问一个范围——通常是控制器和指令(它们的链接函数和/或它们的控制器)——可以设置一个“watchExpression”,AngularJS将对这个范围进行评估。每当AngularJS进入它的$digest循环(特别是“$watch list”循环)时,就会进行这种评估。您可以监视单个范围属性,您可以定义一个函数来监视两个属性,您可以监视数组的长度,等等。
When things happen "inside AngularJS" – e.g., you type into a textbox that has AngularJS two-way databinding enabled (i.e., uses ng-model), an $http callback fires, etc. – $apply has already been called, so we're inside the "AngularJS" rectangle in the figure above. All watchExpressions will be evaluated (possibly more than once – until no further changes are detected).
当事情发生在“AngularJS内部”时——例如,您输入一个启用了AngularJS双向数据库的文本框(例如)。使用ng模型,一个$http回调函数,等等。- $apply已经被调用了,所以我们在上图中的“AngularJS”矩形里面。所有的watchexpression都将被评估(可能不止一次——直到没有进一步的更改被检测到)。
When things happen "outside AngularJS" – e.g., you used bind() in a directive and then that event fires, resulting in your callback being called, or some jQuery registered callback fires – we're still in the "Native" rectangle. If the callback code modifies anything that any $watch is watching, call $apply to get into the AngularJS rectangle, causing the $digest loop to run, and hence AngularJS will notice the change and do its magic.
当事情发生在“AngularJS之外”时——例如,您在一个指令中使用bind(),然后该事件触发,导致调用回调,或者一些jQuery注册回调触发——我们仍然处于“本机”矩形中。如果回调代码修改任何$watch正在查看的内容,那么调用$apply进入AngularJS矩形,导致$digest循环运行,因此AngularJS将注意到这个更改并发挥其神奇的作用。
#3
53
This blog has been covered all that creating examples and understandable explanations.
这个博客已经涵盖了所有的例子和可以理解的解释。
The AngularJS $scope
functions $watch(), $digest()
and $apply()
are some of the central functions in AngularJS. Understanding $watch()
, $digest()
and $apply()
is essential in order to understand AngularJS.
AngularJS $scope函数$watch()、$digest()和$apply()是AngularJS中的一些中心函数。理解$watch()、$digest()和$apply()是理解AngularJS的必要条件。
When you create a data binding from somewhere in your view to a variable on the $scope object, AngularJS creates a "watch" internally. A watch means that AngularJS watches changes in the variable on the $scope object
. The framework is "watching" the variable. Watches are created using the $scope.$watch()
function which I will cover later in this text.
当您从视图中的某个地方创建数据绑定到$scope对象上的变量时,AngularJS在内部创建一个“监视”。监视意味着AngularJS监视$scope对象上变量的更改。框架是“监视”变量。手表是使用$scope.$watch()函数创建的,我将在本文后面介绍这个函数。
At key points in your application AngularJS calls the $scope.$digest()
function. This function iterates through all watches and checks if any of the watched variables have changed. If a watched variable has changed, a corresponding listener function is called. The listener function does whatever work it needs to do, for instance changing an HTML text to reflect the new value of the watched variable. Thus, the $digest()
function is what triggers the data binding to update.
在应用程序的关键位置,AngularJS调用$scope.$digest()函数。这个函数遍历所有的监视并检查是否有任何被监视的变量发生了更改。如果观察到的变量发生了变化,则调用相应的侦听器函数。侦听器函数做它需要做的任何工作,例如更改HTML文本以反映所监视变量的新值。因此,$digest()函数触发数据绑定进行更新。
Most of the time AngularJS will call the $scope.$watch() and $scope.$digest()
functions for you, but in some situations you may have to call them yourself. Therefore it is really good to know how they work.
大多数时候,AngularJS会调用$scope.$watch()和$scope.$digest()函数,但是在某些情况下,您可能不得不自己调用它们。因此,知道它们是如何工作的真的很好。
The $scope.$apply()
function is used to execute some code, and then call $scope.$digest()
after that, so all watches are checked and the corresponding watch listener functions are called. The $apply()
function is useful when integrating AngularJS with other code.
$scope.$apply()函数用于执行一些代码,然后调用$scope.$digest(),然后检查所有的手表并调用相应的watch listener函数。$apply()函数在将AngularJS与其他代码集成时非常有用。
I will get into more detail about the $watch(), $digest()
and $apply()
functions in the remainder of this text.
我将在本文其余部分详细介绍$watch()、$摘要()和$apply()函数。
$watch()
The $scope.watch()
function creates a watch of some variable. When you register a watch you pass two functions as parameters to the $watch()
function:
$scope.watch()函数创建一个变量表。当您注册一个手表时,您将两个函数作为参数传递给$watch()函数:
- A value function
- 值函数
- A listener function
- 一个侦听器函数
Here is an example:
这是一个例子:
$scope.$watch(function() {},
function() {}
);
The first function is the value function and the second function is the listener function.
第一个函数是value函数,第二个函数是listener函数。
The value function should return the value which is being watched. AngularJS can then check the value returned against the value the watch function returned the last time. That way AngularJS can determine if the value has changed. Here is an example:
值函数应该返回正在被监视的值。然后,AngularJS可以根据上次手表函数返回的值检查返回的值。这样,AngularJS就可以确定值是否发生了更改。这是一个例子:
$scope.$watch(function(scope) { return scope.data.myVar },
function() {}
);
This example valule function returns the $scope
variable scope.data.myVar
. If the value of this variable changes, a different value will be returned, and AngularJS will call the listener function.
这个示例valule函数返回$scope变量scope.data. myvar。如果该变量的值发生变化,将返回一个不同的值,AngularJS将调用侦听器函数。
Notice how the value function takes the scope as parameter (without the $ in the name). Via this parameter the value function can access the $scope
and its variables. The value function can also watch global variables instead if you need that, but most often you will watch a $scope
variable.
注意value函数如何将范围作为参数(名称中没有$)。通过这个参数,value函数可以访问$scope和它的变量。如果需要的话,value函数也可以监视全局变量,但是通常您会监视$scope变量。
The listener function should do whatever it needs to do if the value has changed. Perhaps you need to change the content of another variable, or set the content of an HTML element or something. Here is an example:
如果值发生了变化,侦听器函数应该做它需要做的任何事情。也许您需要更改另一个变量的内容,或者设置HTML元素或其他内容的内容。这是一个例子:
$scope.$watch(function(scope) { return scope.data.myVar },
function(newValue, oldValue) {
document.getElementById("").innerHTML =
"" + newValue + "";
}
);
This example sets the inner HTML of an HTML element to the new value of the variable, embedded in the b element which makes the value bold. Of course you could have done this using the code {{ data.myVar }
, but this is just an example of what you can do inside the listener function.
这个例子将HTML元素的内部HTML设置为变量的新值,嵌入在b元素中,使值变得更大胆。当然,您可以使用代码{data来实现这一点。myVar},但这只是一个例子,说明在listener函数中可以做什么。
$digest()
The $scope.$digest()
function iterates through all the watches in the $scope object
, and its child $scope objects (if it has any). When $digest()
iterates over the watches, it calls the value function for each watch. If the value returned by the value function is different than the value it returned the last time it was called, the listener function for that watch is called.
$scope.$digest()函数遍历$scope对象及其子$scope对象(如果有的话)中的所有手表。当$digest()遍历表时,它调用每个表的值函数。如果值函数返回的值与它上次调用时返回的值不同,则调用该表的侦听器函数。
The $digest()
function is called whenever AngularJS thinks it is necessary. For instance, after a button click handler has been executed, or after an AJAX
call returns (after the done() / fail() callback function has been executed).
每当AngularJS认为有必要时,就调用$digest()函数。例如,在执行按钮单击处理程序之后,或者在AJAX调用返回之后(执行done() / fail()回调函数之后)。
You may encounter some corner cases where AngularJS does not call the $digest()
function for you. You will usually detect that by noticing that the data bindings do not update the displayed values. In that case, call $scope.$digest()
and it should work. Or, you can perhaps use $scope.$apply()
instead which I will explain in the next section.
您可能会遇到AngularJS不为您调用$digest()函数的情况。您通常通过注意到数据绑定没有更新显示的值来检测它。在这种情况下,调用$scope.$digest(),它应该工作。或者,您可以使用$scope.$apply(),我将在下一节中对此进行解释。
$apply()
The $scope.$apply()
function takes a function as parameter which is executed, and after that $scope.$digest()
is called internally. That makes it easier for you to make sure that all watches are checked, and thus all data bindings refreshed. Here is an $apply()
example:
函数的作用域为$scope.$apply(),函数的作用域为参数,并在此作用域之后执行。这使您更容易确保检查所有的表,从而刷新所有数据绑定。这里有一个$apply()示例:
$scope.$apply(function() {
$scope.data.myVar = "Another value";
});
The function passed to the $apply()
function as parameter will change the value of $scope.data.myVar
. When the function exits AngularJS will call the $scope.$digest()
function so all watches are checked for changes in the watched values.
传递给$apply()函数的函数作为参数将改变$scope.data.myVar的值。当函数退出时,AngularJS将调用$scope.$digest()函数,以便检查所有手表在监视值中的更改。
Example
To illustrate how $watch()
, $digest(
) and $apply()
works, look at this example:
为了演示$watch()、$digest()和$apply()的工作方式,请看这个示例:
<div ng-controller="myController">
{{data.time}}
<br/>
<button ng-click="updateTime()">update time - ng-click</button>
<button id="updateTimeButton" >update time</button>
</div>
<script>
var module = angular.module("myapp", []);
var myController1 = module.controller("myController", function($scope) {
$scope.data = { time : new Date() };
$scope.updateTime = function() {
$scope.data.time = new Date();
}
document.getElementById("updateTimeButton")
.addEventListener('click', function() {
console.log("update time clicked");
$scope.data.time = new Date();
});
});
</script>
his example binds the $scope.data.time
variable to an interpolation directive which merges the variable value into the HTML page. This binding creates a watch internally on the $scope.data.time variable
.
他的示例绑定了$scope.data。将变量值合并到HTML页面的插补指令的时间变量。此绑定在$scope.data的内部创建一个手表。时间变量。
The example also contains two buttons. The first button has an ng-click
listener attached to it. When that button is clicked the $scope.updateTime()
function is called, and after that AngularJS calls $scope.$digest()
so that data bindings are updated.
该示例还包含两个按钮。第一个按钮附加了一个ng-click侦听器。单击该按钮时,将调用$scope. updatetime()函数,然后AngularJS调用$scope.$digest(),以便更新数据绑定。
The second button gets a standard JavaScript event listener attached to it from inside the controller function. When the second button is clicked that listener function is executed. As you can see, the listener functions for both buttons do almost the same, but when the second button's listener function is called, the data binding is not updated. That is because the $scope.$digest()
is not called after the second button's event listener is executed. Thus, if you click the second button the time is updated in the $scope.data.time
variable, but the new time is never displayed.
第二个按钮从controller函数中获取附加到它的标准JavaScript事件监听器。当单击第二个按钮时,将执行侦听器函数。正如您所看到的,两个按钮的侦听器函数几乎是相同的,但是当第二个按钮的侦听器函数被调用时,数据绑定就不会被更新。这是因为在执行第二个按钮的事件监听器之后不会调用$scope.$digest()。因此,如果单击第二个按钮,时间将在$scope.data中更新。时间变量,但是不会显示新的时间。
To fix that we can add a $scope.$digest()
call to the last line of the button event listener, like this:
为此,我们可以添加一个$scope。
document.getElementById("updateTimeButton")
.addEventListener('click', function() {
console.log("update time clicked");
$scope.data.time = new Date();
$scope.$digest();
});
Instead of calling $digest()
inside the button listener function you could also have used the $apply()
function like this:
除了在button listener函数中调用$digest()之外,您还可以使用$apply()函数,如下所示:
document.getElementById("updateTimeButton")
.addEventListener('click', function() {
$scope.$apply(function() {
console.log("update time clicked");
$scope.data.time = new Date();
});
});
Notice how the $scope.$apply()
function is called from inside the button event listener, and how the update of the $scope.data.time
variable is performed inside the function passed as parameter to the $apply()
function. When the $apply()
function call finishes AngularJS calls $digest()
internally, so all data bindings are updated.
注意$scope.$apply()函数是如何从按钮事件侦听器内部调用的,以及如何更新$scope.data。时间变量在函数中作为参数传递给$apply()函数。当$apply()函数调用在内部完成AngularJS调用$digest()时,所有数据绑定都会更新。
#4
36
AngularJS extends this events-loop, creating something called AngularJS context
.
AngularJS扩展了这个事件循环,创建了一个名为AngularJS的上下文。
$watch()
看()美元
Every time you bind something in the UI you insert a $watch
in a $watch
list.
每次绑定UI中的内容时,都要在$watch列表中插入一个$watch。
User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />
Here we have $scope.user
, which is bound to the first input, and we have $scope.pass
, which is bound to the second one. Doing this we add two $watch
es to the $watch
list.
这里我们有美元范围。用户,它绑定到第一个输入,我们有$scope。传递,它与第二个绑定。为此,我们在$watch列表中添加了两个$watch。
When our template is loaded, AKA in the linking phase, the compiler will look for every directive and creates all the $watch
es that are needed.
当我们的模板被加载时,也就是在链接阶段,编译器将查找每个指令并创建所有需要的$watch。
AngularJS provides $watch
, $watchcollection
and $watch(true)
. Below is a neat diagram explaining all the three taken from watchers in depth.
AngularJS提供$watch、$watchcollection和$watch(true)。下面是一个简洁的图表,解释了从观察者那里获得的三种信息。
angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
function MyCtrl($scope,$timeout) {
$scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];
$scope.$watch("users", function() {
console.log("**** reference checkers $watch ****")
});
$scope.$watchCollection("users", function() {
console.log("**** Collection checkers $watchCollection ****")
});
$scope.$watch("users", function() {
console.log("**** equality checkers with $watch(true) ****")
}, true);
$timeout(function(){
console.log("Triggers All ")
$scope.users = [];
$scope.$digest();
console.log("Triggers $watchCollection and $watch(true)")
$scope.users.push({ name: 'Thalaivar'});
$scope.$digest();
console.log("Triggers $watch(true)")
$scope.users[0].name = 'Superstar';
$scope.$digest();
});
}
http://jsfiddle.net/2Lyn0Lkb/
$digest
loop
When the browser receives an event that can be managed by the AngularJS context the $digest
loop will be fired. This loop is made from two smaller loops. One processes the $evalAsync
queue, and the other one processes the $watch list
. The $digest
will loop through the list of $watch
that we have
当浏览器接收到可以由AngularJS上下文管理的事件时,将触发$digest循环。这个循环由两个较小的循环组成。一个处理$evalAsync队列,另一个处理$watch列表。$摘要将循环遍历我们拥有的$watch列表
app.controller('MainCtrl', function() {
$scope.name = "vinoth";
$scope.changeFoo = function() {
$scope.name = "Thalaivar";
}
});
{{ name }}
<button ng-click="changeFoo()">Change the name</button>
Here we have only one $watch
because ng-click doesn’t create any watches.
这里我们只有一个$watch,因为ng-click不创建任何手表。
We press the button.
我们按下按钮。
- The browser receives an event which will enter the AngularJS context
- 浏览器接收将进入AngularJS上下文的事件
- The
$digest
loop will run and will ask every $watch for changes. - $digest循环将运行,并要求每个$watch进行更改。
- Since the
$watch
which was watching for changes in $scope.name reports a change, it will force another$digest
loop. - 由于在$scope.name中监视更改的$watch报告更改,它将强制执行另一个$digest循环。
- The new loop reports nothing.
- 新的循环没有报告。
- The browser gets the control back and it will update the DOM reflecting the new value of $scope.name
- 浏览器返回控件,并更新DOM以反映$scope.name的新值
- The important thing here is that EVERY event that enters the AngularJS context will run a
$digest
loop. That means that every time we write a letter in an input, the loop will run checking every$watch
in this page. - 这里重要的一点是,每个进入AngularJS上下文的事件都将运行一个$digest循环。这意味着每次我们在输入中写入一个字母时,这个循环将在这个页面中检查每一个$watch。
$apply()
If you call $apply
when an event is fired, it will go through the angular-context, but if you don’t call it, it will run outside it. It is as easy as that. $apply
will call the $digest()
loop internally and it will iterate over all the watches to ensure the DOM is updated with the newly updated value.
如果在触发事件时调用$apply,它将通过angular-context,但是如果不调用它,它将在它之外运行。就这么简单。$apply将在内部调用$digest()循环,它将遍历所有的手表,以确保用新更新的值更新DOM。
The $apply()
method will trigger watchers on the entire $scope
chain whereas the $digest()
method will only trigger watchers on the current $scope
and its children
. When none of the higher-up $scope
objects need to know about the local changes, you can use $digest()
.
$apply()方法将触发整个$scope链上的监视程序,而$digest()方法将只触发当前$scope及其子类的监视程序。当高级的$scope对象不需要知道本地更改时,可以使用$digest()。
#5
17
There are $watchGroup
and $watchCollection
as well. Specifically, $watchGroup
is really helpful if you want to call a function to update an object which has multiple properties in a view that is not dom object, for e.g. other view in canvas, webGL or server request. Here, the documentation link.
还有$watchGroup和$watchCollection。具体来说,$watchGroup非常有用,如果您想调用一个函数来更新一个对象,该对象在视图中有多个属性,而不是dom对象,例如canvas、webGL或服务器请求中的其他视图。这里的文档链接。
#6
15
I found very in-depth videos which cover $watch
, $apply
, $digest
and digest cycles in:
我发现了非常深入的视频,包括$watch、$apply、$digest和digest cycle:
-
AngularJS - Understanding Watcher, $watch, $watchGroup, $watchCollection, ng-change
AngularJS -理解监视者,$watch, $watchGroup, $watchCollection, ng-change
-
AngularJS - Understanding digest cycle (digest phase or digest process or digest loop)
了解消化周期(消化期或消化过程或消化循环)
-
AngularJS Tutorial - Understanding $apply and $digest (in depth)
AngularJS教程-理解$apply和$摘要(深入)
Following are a couple of slides used in those videos to explain the concepts (just in case, if the above links are removed/not working).
以下是这些视频中用来解释这些概念的一些幻灯片(以防万一,如果上面的链接被删除/无效)。
In the above image, "$scope.c" is not being watched as it is not used in any of the data bindings (in markup). The other two ($scope.a
and $scope.b
) will be watched.
在上图中,“$scope”。c"没有被监视,因为它不在任何数据绑定(在标记中)中使用。另外两个美元范围。a和$scope.b)将被监视。
From the above image: Based on the respective browser event, AngularJS captures the event, performs digest cycle (goes through all the watches for changes), execute watch functions and update the DOM. If not browser events, the digest cycle can be manually triggered using $apply
or $digest
.
从上面的图像:基于各自的浏览器事件,AngularJS捕捉事件,执行摘要循环(通过所有的手表进行更改),执行监视功能并更新DOM。如果不是浏览器事件,则可以使用$apply或$digest手动触发摘要循环。
More about $apply
and $digest
:
更多关于$apply和$digest:
#7
9
Just finish reading ALL the above, boring and sleepy (sorry but is true). Very technical, in-depth, detailed, and dry. Why am I writing? Because AngularJS is massive, lots of inter-connected concepts can turn anyone going nuts. I often asked myself, am I not smart enough to understand them? No! It's because so few can explain the tech in a for-dummie language w/o all the terminologies! Okay, let me try:
读完上面的内容,就会感到无聊和困倦(抱歉,但这是真的)。非常专业,深入,详细,干燥。我为什么要写作?因为AngularJS非常庞大,很多相互联系的概念会让任何人发疯。我经常问自己,我是否聪明到理解它们?不!这是因为很少有人能用一种愚蠢的语言来解释这个技术,所有的术语都是如此!好的,让我试一试:
1) They are all event-driven things. (I hear the laugh, but read on)
1)都是事件驱动的。(我听到笑声,但继续读下去)
If you don't know what event-driven is Then think you place a button on the page, hook it up w/ a function using "on-click", waiting for users to click on it to trigger the actions you plant inside the function. Or think of "trigger" of SQL Server / Oracle.
如果你不知道事件驱动是什么,那么就把一个按钮放在页面上,用“on-click”把它连接到一个函数上,等待用户点击它来触发你在函数中植入的动作。或者想想SQL Server / Oracle的“触发器”。
2) $watch is "on-click".
2)美元的手表“点击”。
What's special about is it takes 2 functions as parameters, first one gives the value from the event, second one takes the value into consideration...
它的特别之处在于它以两个函数作为参数,第一个函数给出事件的值,第二个函数考虑值……
3) $digest is the boss who checks around tirelessly, bla-bla-bla but a good boss.
3)《美元文摘》是指那种不知疲倦、喋喋不休、但却是个好老板的老板。
4) $apply gives you the way when you want to do it manually, like a fail-proof (in case on-click doesn't kick in, you force it to run.)
4)当你想手动操作时,$apply给你提供了一种方法,就像一个防故障的(如果不启动,你就强迫它运行)。
Now, let's make it visual. Picture this to make it even more easy to grab the idea:
现在,让我们把它视觉化。想象一下,让你更容易理解这个想法:
In a restaurant,
在一个餐厅,
- WAITERS are supposed to take orders from customers, this is
服务员应该接受顾客的命令,这是
$watch(
function(){return orders;},
function(){Kitchen make it;}
);
- MANAGER running around to make sure all waiters are awake, responsive to any sign of changes from customers. This is $digest()
-经理跑来跑去,确保所有的服务员都醒着,对顾客的任何变化做出反应。这是美元消化()
- OWNER has the ultimate power to drive everyone upon request, this is $apply()
-业主有最终的权力驱使每个人的要求,这是$apply()
#1
1630
You need to be aware about how AngularJS works in order to understand it.
你需要了解AngularJS是如何工作的,才能理解它。
Digest cycle and $scope
First and foremost, AngularJS defines a concept of a so-called digest cycle. This cycle can be considered as a loop, during which AngularJS checks if there are any changes to all the variables watched by all the $scope
s. So if you have $scope.myVar
defined in your controller and this variable was marked for being watched, then you are implicitly telling AngularJS to monitor the changes on myVar
in each iteration of the loop.
首先也是最重要的是,AngularJS定义了所谓的消化循环的概念。这个循环可以看作一个循环,在这个循环中,AngularJS检查所有$作用域监视的所有变量是否有任何更改。如果你有$scope。在控制器中定义的myVar,这个变量被标记为被监视,然后隐式地告诉AngularJS在循环的每次迭代中监视myVar上的变化。
A natural follow-up question would be: Is everything attached to $scope
being watched? Fortunately, no. If you would watch for changes to every object in your $scope
, then quickly a digest loop would take ages to evaluate and you would quickly run into performance issues. That is why the AngularJS team gave us two ways of declaring some $scope
variable as being watched (read below).
一个自然的后续问题是:所有与$scope相关的东西都在被监视吗?幸运的是,没有。如果您要监视对$范围内的每个对象的更改,那么很快就会需要很长时间来评估一个摘要循环,您将很快遇到性能问题。这就是为什么AngularJS团队给了我们两种方法来声明某个$scope变量作为监视对象(请参阅下面的内容)。
$watch helps to listen for $scope changes
There are two ways of declaring a $scope
variable as being watched.
有两种方法可以声明要监视的$scope变量。
- By using it in your template via the expression
<span>{{myVar}}</span>
- 通过在模板中通过表达式{{myVar} 使用它
- By adding it manually via the
$watch
service - 通过$watch服务手动添加它。
Ad 1) This is the most common scenario and I'm sure you've seen it before, but you didn't know that this has created a watch in the background. Yes, it had! Using AngularJS directives (such as ng-repeat
) can also create implicit watches.
Ad 1)这是最常见的场景,我敢肯定你以前见过,但你不知道它在后台创建了一个手表。是的,它有!使用AngularJS指令(例如ng-repeat)也可以创建隐式表。
Ad 2) This is how you create your own watches. $watch
service helps you to run some code when some value attached to the $scope
has changed. It is rarely used, but sometimes is helpful. For instance, if you want to run some code each time 'myVar' changes, you could do the following:
这就是你如何创建自己的手表。$watch服务帮助您运行一些代码,当附加到$scope的值发生变化时。它很少被使用,但有时是有用的。例如,如果您希望在每次“myVar”更改时运行一些代码,您可以执行以下操作:
function MyController($scope) {
$scope.myVar = 1;
$scope.$watch('myVar', function() {
alert('hey, myVar has changed!');
});
$scope.buttonClicked = function() {
$scope.myVar = 2; // This will trigger $watch expression to kick in
};
}
$apply enables to integrate changes with the digest cycle
You can think of the $apply
function as of an integration mechanism. You see, each time you change some watched variable attached to the $scope
object directly, AngularJS will know that the change has happened. This is because AngularJS already knew to monitor those changes. So if it happens in code managed by the framework, the digest cycle will carry on.
您可以将$apply函数看作是一种集成机制。您可以看到,每当您更改一个直接连接到$scope对象的受监视变量时,AngularJS将知道所发生的更改。这是因为AngularJS已经知道要监控这些变化。因此,如果它发生在由框架管理的代码中,那么摘要循环将继续下去。
However, sometimes you want to change some value outside of the AngularJS world and see the changes propagate normally. Consider this - you have a $scope.myVar
value which will be modified within a jQuery's $.ajax()
handler. This will happen at some point in future. AngularJS can't wait for this to happen, since it hasn't been instructed to wait on jQuery.
然而,有时您希望在AngularJS世界之外更改一些值,并看到更改正常传播。考虑到这一点——您有一个$范围。将在jQuery $.ajax()处理程序中修改的myVar值。这将在未来的某个时刻发生。AngularJS都等不及了,因为它还没有被指示要等待jQuery。
To tackle this, $apply
has been introduced. It lets you start the digestion cycle explicitly. However, you should only use this to migrate some data to AngularJS (integration with other frameworks), but never use this method combined with regular AngularJS code, as AngularJS will throw an error then.
为了解决这个问题,我们引入了$apply。它可以让你明确地开始消化循环。但是,您应该只使用此方法将一些数据迁移到AngularJS(与其他框架集成)中,但不要将此方法与常规的AngularJS代码结合使用,因为AngularJS会抛出错误。
How is all of this related to the DOM?
Well, you should really follow the tutorial again, now that you know all this. The digest cycle will make sure that the UI and the JavaScript code stay synchronised, by evaluating every watcher attached to all $scope
s as long as nothing changes. If no more changes happen in the digest loop, then it's considered to be finished.
好吧,既然你已经知道了这些,你应该再看一遍教程。摘要周期将通过评估每个附加到所有$作用域的观察者(只要不发生任何变化)来确保UI和JavaScript代码保持同步。如果在摘要循环中没有发生任何更改,则认为已完成。
You can attach objects to the $scope
object either explicitly in the Controller, or by declaring them in {{expression}}
form directly in the view.
可以在控制器中显式地将对象附加到$scope对象,也可以通过在视图中直接在{{{expression}}}窗体中声明对象。
I hope that helps to clarify some basic knowledge about all this.
我希望这有助于澄清关于这一切的一些基本知识。
Further readings:
进一步阅读:
- Make Your Own AngularJS, Part 1: Scopes And Digest
- 制作你自己的AngularJS,第1部分:作用域和摘要
#2
151
In AngularJS, we update our models, and our views/templates update the DOM "automatically" (via built-in or custom directives).
在AngularJS中,我们更新模型,我们的视图/模板“自动”更新DOM(通过内置或自定义指令)。
$apply and $watch, both being Scope methods, are not related to the DOM.
$apply和$watch都是范围方法,与DOM无关。
The Concepts page (section "Runtime") has a pretty good explanation of the $digest loop, $apply, the $evalAsync queue and the $watch list. Here's the picture that accompanies the text:
concept页面(“Runtime”部分)对$digest循环、$apply、$evalAsync队列和$watch列表有很好的解释。这是伴随文字的图片:
Whatever code has access to a scope – normally controllers and directives (their link functions and/or their controllers) – can set up a "watchExpression" that AngularJS will evaluate against that scope. This evaluation happens whenever AngularJS enters its $digest loop (in particular, the "$watch list" loop). You can watch individual scope properties, you can define a function to watch two properties together, you can watch the length of an array, etc.
任何代码都可以访问一个范围——通常是控制器和指令(它们的链接函数和/或它们的控制器)——可以设置一个“watchExpression”,AngularJS将对这个范围进行评估。每当AngularJS进入它的$digest循环(特别是“$watch list”循环)时,就会进行这种评估。您可以监视单个范围属性,您可以定义一个函数来监视两个属性,您可以监视数组的长度,等等。
When things happen "inside AngularJS" – e.g., you type into a textbox that has AngularJS two-way databinding enabled (i.e., uses ng-model), an $http callback fires, etc. – $apply has already been called, so we're inside the "AngularJS" rectangle in the figure above. All watchExpressions will be evaluated (possibly more than once – until no further changes are detected).
当事情发生在“AngularJS内部”时——例如,您输入一个启用了AngularJS双向数据库的文本框(例如)。使用ng模型,一个$http回调函数,等等。- $apply已经被调用了,所以我们在上图中的“AngularJS”矩形里面。所有的watchexpression都将被评估(可能不止一次——直到没有进一步的更改被检测到)。
When things happen "outside AngularJS" – e.g., you used bind() in a directive and then that event fires, resulting in your callback being called, or some jQuery registered callback fires – we're still in the "Native" rectangle. If the callback code modifies anything that any $watch is watching, call $apply to get into the AngularJS rectangle, causing the $digest loop to run, and hence AngularJS will notice the change and do its magic.
当事情发生在“AngularJS之外”时——例如,您在一个指令中使用bind(),然后该事件触发,导致调用回调,或者一些jQuery注册回调触发——我们仍然处于“本机”矩形中。如果回调代码修改任何$watch正在查看的内容,那么调用$apply进入AngularJS矩形,导致$digest循环运行,因此AngularJS将注意到这个更改并发挥其神奇的作用。
#3
53
This blog has been covered all that creating examples and understandable explanations.
这个博客已经涵盖了所有的例子和可以理解的解释。
The AngularJS $scope
functions $watch(), $digest()
and $apply()
are some of the central functions in AngularJS. Understanding $watch()
, $digest()
and $apply()
is essential in order to understand AngularJS.
AngularJS $scope函数$watch()、$digest()和$apply()是AngularJS中的一些中心函数。理解$watch()、$digest()和$apply()是理解AngularJS的必要条件。
When you create a data binding from somewhere in your view to a variable on the $scope object, AngularJS creates a "watch" internally. A watch means that AngularJS watches changes in the variable on the $scope object
. The framework is "watching" the variable. Watches are created using the $scope.$watch()
function which I will cover later in this text.
当您从视图中的某个地方创建数据绑定到$scope对象上的变量时,AngularJS在内部创建一个“监视”。监视意味着AngularJS监视$scope对象上变量的更改。框架是“监视”变量。手表是使用$scope.$watch()函数创建的,我将在本文后面介绍这个函数。
At key points in your application AngularJS calls the $scope.$digest()
function. This function iterates through all watches and checks if any of the watched variables have changed. If a watched variable has changed, a corresponding listener function is called. The listener function does whatever work it needs to do, for instance changing an HTML text to reflect the new value of the watched variable. Thus, the $digest()
function is what triggers the data binding to update.
在应用程序的关键位置,AngularJS调用$scope.$digest()函数。这个函数遍历所有的监视并检查是否有任何被监视的变量发生了更改。如果观察到的变量发生了变化,则调用相应的侦听器函数。侦听器函数做它需要做的任何工作,例如更改HTML文本以反映所监视变量的新值。因此,$digest()函数触发数据绑定进行更新。
Most of the time AngularJS will call the $scope.$watch() and $scope.$digest()
functions for you, but in some situations you may have to call them yourself. Therefore it is really good to know how they work.
大多数时候,AngularJS会调用$scope.$watch()和$scope.$digest()函数,但是在某些情况下,您可能不得不自己调用它们。因此,知道它们是如何工作的真的很好。
The $scope.$apply()
function is used to execute some code, and then call $scope.$digest()
after that, so all watches are checked and the corresponding watch listener functions are called. The $apply()
function is useful when integrating AngularJS with other code.
$scope.$apply()函数用于执行一些代码,然后调用$scope.$digest(),然后检查所有的手表并调用相应的watch listener函数。$apply()函数在将AngularJS与其他代码集成时非常有用。
I will get into more detail about the $watch(), $digest()
and $apply()
functions in the remainder of this text.
我将在本文其余部分详细介绍$watch()、$摘要()和$apply()函数。
$watch()
The $scope.watch()
function creates a watch of some variable. When you register a watch you pass two functions as parameters to the $watch()
function:
$scope.watch()函数创建一个变量表。当您注册一个手表时,您将两个函数作为参数传递给$watch()函数:
- A value function
- 值函数
- A listener function
- 一个侦听器函数
Here is an example:
这是一个例子:
$scope.$watch(function() {},
function() {}
);
The first function is the value function and the second function is the listener function.
第一个函数是value函数,第二个函数是listener函数。
The value function should return the value which is being watched. AngularJS can then check the value returned against the value the watch function returned the last time. That way AngularJS can determine if the value has changed. Here is an example:
值函数应该返回正在被监视的值。然后,AngularJS可以根据上次手表函数返回的值检查返回的值。这样,AngularJS就可以确定值是否发生了更改。这是一个例子:
$scope.$watch(function(scope) { return scope.data.myVar },
function() {}
);
This example valule function returns the $scope
variable scope.data.myVar
. If the value of this variable changes, a different value will be returned, and AngularJS will call the listener function.
这个示例valule函数返回$scope变量scope.data. myvar。如果该变量的值发生变化,将返回一个不同的值,AngularJS将调用侦听器函数。
Notice how the value function takes the scope as parameter (without the $ in the name). Via this parameter the value function can access the $scope
and its variables. The value function can also watch global variables instead if you need that, but most often you will watch a $scope
variable.
注意value函数如何将范围作为参数(名称中没有$)。通过这个参数,value函数可以访问$scope和它的变量。如果需要的话,value函数也可以监视全局变量,但是通常您会监视$scope变量。
The listener function should do whatever it needs to do if the value has changed. Perhaps you need to change the content of another variable, or set the content of an HTML element or something. Here is an example:
如果值发生了变化,侦听器函数应该做它需要做的任何事情。也许您需要更改另一个变量的内容,或者设置HTML元素或其他内容的内容。这是一个例子:
$scope.$watch(function(scope) { return scope.data.myVar },
function(newValue, oldValue) {
document.getElementById("").innerHTML =
"" + newValue + "";
}
);
This example sets the inner HTML of an HTML element to the new value of the variable, embedded in the b element which makes the value bold. Of course you could have done this using the code {{ data.myVar }
, but this is just an example of what you can do inside the listener function.
这个例子将HTML元素的内部HTML设置为变量的新值,嵌入在b元素中,使值变得更大胆。当然,您可以使用代码{data来实现这一点。myVar},但这只是一个例子,说明在listener函数中可以做什么。
$digest()
The $scope.$digest()
function iterates through all the watches in the $scope object
, and its child $scope objects (if it has any). When $digest()
iterates over the watches, it calls the value function for each watch. If the value returned by the value function is different than the value it returned the last time it was called, the listener function for that watch is called.
$scope.$digest()函数遍历$scope对象及其子$scope对象(如果有的话)中的所有手表。当$digest()遍历表时,它调用每个表的值函数。如果值函数返回的值与它上次调用时返回的值不同,则调用该表的侦听器函数。
The $digest()
function is called whenever AngularJS thinks it is necessary. For instance, after a button click handler has been executed, or after an AJAX
call returns (after the done() / fail() callback function has been executed).
每当AngularJS认为有必要时,就调用$digest()函数。例如,在执行按钮单击处理程序之后,或者在AJAX调用返回之后(执行done() / fail()回调函数之后)。
You may encounter some corner cases where AngularJS does not call the $digest()
function for you. You will usually detect that by noticing that the data bindings do not update the displayed values. In that case, call $scope.$digest()
and it should work. Or, you can perhaps use $scope.$apply()
instead which I will explain in the next section.
您可能会遇到AngularJS不为您调用$digest()函数的情况。您通常通过注意到数据绑定没有更新显示的值来检测它。在这种情况下,调用$scope.$digest(),它应该工作。或者,您可以使用$scope.$apply(),我将在下一节中对此进行解释。
$apply()
The $scope.$apply()
function takes a function as parameter which is executed, and after that $scope.$digest()
is called internally. That makes it easier for you to make sure that all watches are checked, and thus all data bindings refreshed. Here is an $apply()
example:
函数的作用域为$scope.$apply(),函数的作用域为参数,并在此作用域之后执行。这使您更容易确保检查所有的表,从而刷新所有数据绑定。这里有一个$apply()示例:
$scope.$apply(function() {
$scope.data.myVar = "Another value";
});
The function passed to the $apply()
function as parameter will change the value of $scope.data.myVar
. When the function exits AngularJS will call the $scope.$digest()
function so all watches are checked for changes in the watched values.
传递给$apply()函数的函数作为参数将改变$scope.data.myVar的值。当函数退出时,AngularJS将调用$scope.$digest()函数,以便检查所有手表在监视值中的更改。
Example
To illustrate how $watch()
, $digest(
) and $apply()
works, look at this example:
为了演示$watch()、$digest()和$apply()的工作方式,请看这个示例:
<div ng-controller="myController">
{{data.time}}
<br/>
<button ng-click="updateTime()">update time - ng-click</button>
<button id="updateTimeButton" >update time</button>
</div>
<script>
var module = angular.module("myapp", []);
var myController1 = module.controller("myController", function($scope) {
$scope.data = { time : new Date() };
$scope.updateTime = function() {
$scope.data.time = new Date();
}
document.getElementById("updateTimeButton")
.addEventListener('click', function() {
console.log("update time clicked");
$scope.data.time = new Date();
});
});
</script>
his example binds the $scope.data.time
variable to an interpolation directive which merges the variable value into the HTML page. This binding creates a watch internally on the $scope.data.time variable
.
他的示例绑定了$scope.data。将变量值合并到HTML页面的插补指令的时间变量。此绑定在$scope.data的内部创建一个手表。时间变量。
The example also contains two buttons. The first button has an ng-click
listener attached to it. When that button is clicked the $scope.updateTime()
function is called, and after that AngularJS calls $scope.$digest()
so that data bindings are updated.
该示例还包含两个按钮。第一个按钮附加了一个ng-click侦听器。单击该按钮时,将调用$scope. updatetime()函数,然后AngularJS调用$scope.$digest(),以便更新数据绑定。
The second button gets a standard JavaScript event listener attached to it from inside the controller function. When the second button is clicked that listener function is executed. As you can see, the listener functions for both buttons do almost the same, but when the second button's listener function is called, the data binding is not updated. That is because the $scope.$digest()
is not called after the second button's event listener is executed. Thus, if you click the second button the time is updated in the $scope.data.time
variable, but the new time is never displayed.
第二个按钮从controller函数中获取附加到它的标准JavaScript事件监听器。当单击第二个按钮时,将执行侦听器函数。正如您所看到的,两个按钮的侦听器函数几乎是相同的,但是当第二个按钮的侦听器函数被调用时,数据绑定就不会被更新。这是因为在执行第二个按钮的事件监听器之后不会调用$scope.$digest()。因此,如果单击第二个按钮,时间将在$scope.data中更新。时间变量,但是不会显示新的时间。
To fix that we can add a $scope.$digest()
call to the last line of the button event listener, like this:
为此,我们可以添加一个$scope。
document.getElementById("updateTimeButton")
.addEventListener('click', function() {
console.log("update time clicked");
$scope.data.time = new Date();
$scope.$digest();
});
Instead of calling $digest()
inside the button listener function you could also have used the $apply()
function like this:
除了在button listener函数中调用$digest()之外,您还可以使用$apply()函数,如下所示:
document.getElementById("updateTimeButton")
.addEventListener('click', function() {
$scope.$apply(function() {
console.log("update time clicked");
$scope.data.time = new Date();
});
});
Notice how the $scope.$apply()
function is called from inside the button event listener, and how the update of the $scope.data.time
variable is performed inside the function passed as parameter to the $apply()
function. When the $apply()
function call finishes AngularJS calls $digest()
internally, so all data bindings are updated.
注意$scope.$apply()函数是如何从按钮事件侦听器内部调用的,以及如何更新$scope.data。时间变量在函数中作为参数传递给$apply()函数。当$apply()函数调用在内部完成AngularJS调用$digest()时,所有数据绑定都会更新。
#4
36
AngularJS extends this events-loop, creating something called AngularJS context
.
AngularJS扩展了这个事件循环,创建了一个名为AngularJS的上下文。
$watch()
看()美元
Every time you bind something in the UI you insert a $watch
in a $watch
list.
每次绑定UI中的内容时,都要在$watch列表中插入一个$watch。
User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />
Here we have $scope.user
, which is bound to the first input, and we have $scope.pass
, which is bound to the second one. Doing this we add two $watch
es to the $watch
list.
这里我们有美元范围。用户,它绑定到第一个输入,我们有$scope。传递,它与第二个绑定。为此,我们在$watch列表中添加了两个$watch。
When our template is loaded, AKA in the linking phase, the compiler will look for every directive and creates all the $watch
es that are needed.
当我们的模板被加载时,也就是在链接阶段,编译器将查找每个指令并创建所有需要的$watch。
AngularJS provides $watch
, $watchcollection
and $watch(true)
. Below is a neat diagram explaining all the three taken from watchers in depth.
AngularJS提供$watch、$watchcollection和$watch(true)。下面是一个简洁的图表,解释了从观察者那里获得的三种信息。
angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
function MyCtrl($scope,$timeout) {
$scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];
$scope.$watch("users", function() {
console.log("**** reference checkers $watch ****")
});
$scope.$watchCollection("users", function() {
console.log("**** Collection checkers $watchCollection ****")
});
$scope.$watch("users", function() {
console.log("**** equality checkers with $watch(true) ****")
}, true);
$timeout(function(){
console.log("Triggers All ")
$scope.users = [];
$scope.$digest();
console.log("Triggers $watchCollection and $watch(true)")
$scope.users.push({ name: 'Thalaivar'});
$scope.$digest();
console.log("Triggers $watch(true)")
$scope.users[0].name = 'Superstar';
$scope.$digest();
});
}
http://jsfiddle.net/2Lyn0Lkb/
$digest
loop
When the browser receives an event that can be managed by the AngularJS context the $digest
loop will be fired. This loop is made from two smaller loops. One processes the $evalAsync
queue, and the other one processes the $watch list
. The $digest
will loop through the list of $watch
that we have
当浏览器接收到可以由AngularJS上下文管理的事件时,将触发$digest循环。这个循环由两个较小的循环组成。一个处理$evalAsync队列,另一个处理$watch列表。$摘要将循环遍历我们拥有的$watch列表
app.controller('MainCtrl', function() {
$scope.name = "vinoth";
$scope.changeFoo = function() {
$scope.name = "Thalaivar";
}
});
{{ name }}
<button ng-click="changeFoo()">Change the name</button>
Here we have only one $watch
because ng-click doesn’t create any watches.
这里我们只有一个$watch,因为ng-click不创建任何手表。
We press the button.
我们按下按钮。
- The browser receives an event which will enter the AngularJS context
- 浏览器接收将进入AngularJS上下文的事件
- The
$digest
loop will run and will ask every $watch for changes. - $digest循环将运行,并要求每个$watch进行更改。
- Since the
$watch
which was watching for changes in $scope.name reports a change, it will force another$digest
loop. - 由于在$scope.name中监视更改的$watch报告更改,它将强制执行另一个$digest循环。
- The new loop reports nothing.
- 新的循环没有报告。
- The browser gets the control back and it will update the DOM reflecting the new value of $scope.name
- 浏览器返回控件,并更新DOM以反映$scope.name的新值
- The important thing here is that EVERY event that enters the AngularJS context will run a
$digest
loop. That means that every time we write a letter in an input, the loop will run checking every$watch
in this page. - 这里重要的一点是,每个进入AngularJS上下文的事件都将运行一个$digest循环。这意味着每次我们在输入中写入一个字母时,这个循环将在这个页面中检查每一个$watch。
$apply()
If you call $apply
when an event is fired, it will go through the angular-context, but if you don’t call it, it will run outside it. It is as easy as that. $apply
will call the $digest()
loop internally and it will iterate over all the watches to ensure the DOM is updated with the newly updated value.
如果在触发事件时调用$apply,它将通过angular-context,但是如果不调用它,它将在它之外运行。就这么简单。$apply将在内部调用$digest()循环,它将遍历所有的手表,以确保用新更新的值更新DOM。
The $apply()
method will trigger watchers on the entire $scope
chain whereas the $digest()
method will only trigger watchers on the current $scope
and its children
. When none of the higher-up $scope
objects need to know about the local changes, you can use $digest()
.
$apply()方法将触发整个$scope链上的监视程序,而$digest()方法将只触发当前$scope及其子类的监视程序。当高级的$scope对象不需要知道本地更改时,可以使用$digest()。
#5
17
There are $watchGroup
and $watchCollection
as well. Specifically, $watchGroup
is really helpful if you want to call a function to update an object which has multiple properties in a view that is not dom object, for e.g. other view in canvas, webGL or server request. Here, the documentation link.
还有$watchGroup和$watchCollection。具体来说,$watchGroup非常有用,如果您想调用一个函数来更新一个对象,该对象在视图中有多个属性,而不是dom对象,例如canvas、webGL或服务器请求中的其他视图。这里的文档链接。
#6
15
I found very in-depth videos which cover $watch
, $apply
, $digest
and digest cycles in:
我发现了非常深入的视频,包括$watch、$apply、$digest和digest cycle:
-
AngularJS - Understanding Watcher, $watch, $watchGroup, $watchCollection, ng-change
AngularJS -理解监视者,$watch, $watchGroup, $watchCollection, ng-change
-
AngularJS - Understanding digest cycle (digest phase or digest process or digest loop)
了解消化周期(消化期或消化过程或消化循环)
-
AngularJS Tutorial - Understanding $apply and $digest (in depth)
AngularJS教程-理解$apply和$摘要(深入)
Following are a couple of slides used in those videos to explain the concepts (just in case, if the above links are removed/not working).
以下是这些视频中用来解释这些概念的一些幻灯片(以防万一,如果上面的链接被删除/无效)。
In the above image, "$scope.c" is not being watched as it is not used in any of the data bindings (in markup). The other two ($scope.a
and $scope.b
) will be watched.
在上图中,“$scope”。c"没有被监视,因为它不在任何数据绑定(在标记中)中使用。另外两个美元范围。a和$scope.b)将被监视。
From the above image: Based on the respective browser event, AngularJS captures the event, performs digest cycle (goes through all the watches for changes), execute watch functions and update the DOM. If not browser events, the digest cycle can be manually triggered using $apply
or $digest
.
从上面的图像:基于各自的浏览器事件,AngularJS捕捉事件,执行摘要循环(通过所有的手表进行更改),执行监视功能并更新DOM。如果不是浏览器事件,则可以使用$apply或$digest手动触发摘要循环。
More about $apply
and $digest
:
更多关于$apply和$digest:
#7
9
Just finish reading ALL the above, boring and sleepy (sorry but is true). Very technical, in-depth, detailed, and dry. Why am I writing? Because AngularJS is massive, lots of inter-connected concepts can turn anyone going nuts. I often asked myself, am I not smart enough to understand them? No! It's because so few can explain the tech in a for-dummie language w/o all the terminologies! Okay, let me try:
读完上面的内容,就会感到无聊和困倦(抱歉,但这是真的)。非常专业,深入,详细,干燥。我为什么要写作?因为AngularJS非常庞大,很多相互联系的概念会让任何人发疯。我经常问自己,我是否聪明到理解它们?不!这是因为很少有人能用一种愚蠢的语言来解释这个技术,所有的术语都是如此!好的,让我试一试:
1) They are all event-driven things. (I hear the laugh, but read on)
1)都是事件驱动的。(我听到笑声,但继续读下去)
If you don't know what event-driven is Then think you place a button on the page, hook it up w/ a function using "on-click", waiting for users to click on it to trigger the actions you plant inside the function. Or think of "trigger" of SQL Server / Oracle.
如果你不知道事件驱动是什么,那么就把一个按钮放在页面上,用“on-click”把它连接到一个函数上,等待用户点击它来触发你在函数中植入的动作。或者想想SQL Server / Oracle的“触发器”。
2) $watch is "on-click".
2)美元的手表“点击”。
What's special about is it takes 2 functions as parameters, first one gives the value from the event, second one takes the value into consideration...
它的特别之处在于它以两个函数作为参数,第一个函数给出事件的值,第二个函数考虑值……
3) $digest is the boss who checks around tirelessly, bla-bla-bla but a good boss.
3)《美元文摘》是指那种不知疲倦、喋喋不休、但却是个好老板的老板。
4) $apply gives you the way when you want to do it manually, like a fail-proof (in case on-click doesn't kick in, you force it to run.)
4)当你想手动操作时,$apply给你提供了一种方法,就像一个防故障的(如果不启动,你就强迫它运行)。
Now, let's make it visual. Picture this to make it even more easy to grab the idea:
现在,让我们把它视觉化。想象一下,让你更容易理解这个想法:
In a restaurant,
在一个餐厅,
- WAITERS are supposed to take orders from customers, this is
服务员应该接受顾客的命令,这是
$watch(
function(){return orders;},
function(){Kitchen make it;}
);
- MANAGER running around to make sure all waiters are awake, responsive to any sign of changes from customers. This is $digest()
-经理跑来跑去,确保所有的服务员都醒着,对顾客的任何变化做出反应。这是美元消化()
- OWNER has the ultimate power to drive everyone upon request, this is $apply()
-业主有最终的权力驱使每个人的要求,这是$apply()