Home  >  Article  >  Web Front-end  >  Detailed explanation of $apply() method in angularJS_AngularJS

Detailed explanation of $apply() method in angularJS_AngularJS

WBOY
WBOYOriginal
2016-05-16 16:21:461186browse

For me, a complete novice in the front-end, I still know little about Javascript. If I want to get started with angular JS directly, I encounter a lot of resistance. However, I believe that as long as we work hard, even anti-human designs will not be a big problem.

Okay, no more nonsense. In order to understand what angular JS is, I started with Scope. So what is Scope? Borrowing a passage from the official document:

Copy code The code is as follows:

"scope is an object that refers to the application model. It is an execution context for expressions. Scopes are arranged in hierarchical structure which mimic the DOM structure of the application. Scopes can watch expressions and propagate events."

After reading this, by analogy to other programming languages, I feel that Scope is like the scope of the Data Model, providing context for the execution of Expressions. Let’s understand it this way for now.

Features of Scope

Next, let’s see what features Scope has?

Scope provides the $watch method to monitor Model changes.
Scope provides the $apply method to propagate Model changes.
Scope can be inherited to isolate different application components and property access permissions.
Scope provides context for the evaluation of Expressions.

Regarding these four features, because I have studied ActionScript, C, and Java before, the first, third, and fourth points are not difficult to understand, but the second point feels a bit unclear. In line with the principle of asking for answers, I still found some things through Google. For experienced veterans, please tap on the bricks!

Origin Javascript

First of all, at first glance, scope.apply() seems to be an ordinary method for updating bindings. But think a little more, why do we need it? When is it usually used? To understand these two issues, we have to start with Javascript. In Javascript code, it is executed in a certain order. When it is the turn of a code fragment to be executed, the browser will only execute the current fragment and will not do anything else. So sometimes some web pages that are not very well made will get stuck after clicking on something. The way Javascript works is one of the reasons for this phenomenon! Below we have a piece of code to feel it:

Copy code The code is as follows:

var button = document.getElementById('clickMe');
function buttonClicked () {
alert('the button was clicked');
}
button.addEventListener('click', buttonClicked);
function timerComplete () {
alert('timer complete');
}
setTimeout(timerComplete, 5000);

When loading Javascript code, first find a button with an id called "clickMe", then add a listener, and then set a timeout. Wait 5 seconds and a dialog box will pop up. If you refresh the page and click the clickMe button immediately, a dialog box will pop up. If you don't click OK, the timerComplete function will never have a chance to execute.

How to update bindings

Okay, after talking about some seemingly irrelevant things, let’s get back to the topic. How does angular JS know when data changes and the page needs to be updated? The code needs to know when the data has been modified, but there is currently no way to directly notify that the data on an object has changed (although ECMAScript 5 is trying to solve this problem, it is still in the experimental stage). The currently more mainstream strategies include the following two solutions. One is to use a special object so that all data can only be set by calling the object's method instead of directly specifying it through the property. In this way, all modifications can be recorded, and you will know when the page needs to be updated. The disadvantage of this is that we must inherit a special object. Assignment can only be done through object.set('key', 'value') instead of object.key=value. In frameworks, like EmberJS and KnockoutJS do this (although I have never been exposed to it - embarrassing). The other is the method adopted by angular JS, which checks whether there are any data changes after each Javascript code execution sequence is executed. This seems inefficient and may even seriously impact performance. However, angular JS uses some clever methods to solve this problem (it has not been studied yet, and it is not clear yet). The advantage of this is that we can use any object at will, there are no restrictions on the assignment method, and we can also detect changes in the data.
For this solution adopted by angular JS, what we care about is when the data changes, and this is where scope.apply() comes in handy. Checking whether the bound data has changed is actually done by scope.digest(), but we almost never call this method directly, but call the scope.apply() method because in scope In the .apply() method, it will call the scope.digest() method. The scope.apply() method takes a function or expression, executes it, and finally calls the scope.digest() method to update bindings or watchers.

When to use $apply()

It’s still the same question, when do we need to call the apply() method? The situation is very rare. In fact, almost all our code is wrapped in scope.apply(), such as ng-click, controller initialization, http callback function, etc. In these cases, we don't need to call it ourselves. In fact, we can't call it ourselves, otherwise calling the apply() method inside the apply() method will throw an error. We really need to use it if we need to run the code in a new execution sequence, and if and only if this new execution sequence is not created by the angular JS library method, at this time we need to use scope for the code. apply() wrapped. Let’s use an example to explain:

Copy code The code is as follows:

{{message}}

Copy code The code is as follows:

functionCtrl($scope) {
$scope.message ="Waiting 2000ms for update";
setTimeout(function () {
​ ​$scope.message="Timeout called!";
// AngularJS unaware of update to $scope
}, 2000);
}

After the above code is executed, the page will display: Waiting 2000ms for update. Apparently the data update is not noticed by angular JS.
Next, we slightly modify the Javascript code and wrap it with scope.apply().

Copy code The code is as follows:

functionCtrl($scope) {
$scope.message ="Waiting 2000ms for update";
setTimeout(function () {
​ ​$scope.$apply(function () {
​ ​ ​$scope.message="Timeout called!";
});
}, 2000);
}

The difference this time is that the page will first display: Waiting 2000ms for update. After waiting for 2 seconds, the content will be changed to: Timeout called!. Obviously the data update is noticed by angular JS.
NOTE: We should not do this, but use the timeout method provided by angular JS, so that it will be automatically wrapped with the apply method.

Science is a double-edged sword
Finally, let’s take another look at the scope.apply() and scope.apply(function) methods! Although angular JS has done a lot for us, we have also lost some opportunities. You can tell at a glance from the pseudocode below:

Copy code The code is as follows:

function$apply(expr) {
try {
​​return$eval(expr);
} catch(e) {
​​$exceptionHandler(e);
} finally {
​​$root.$digest();
}
}

It will catch all exceptions and will not throw them again. Finally, the $digest() method will be called.

To summarize

The $apply() method can execute angular JS expressions outside the angular framework, such as DOM events, setTimeout, XHR or other third-party libraries. This is just the beginning, the water is still very deep, everyone is welcome to take a deep dive together!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn