The development of jquery is fast, with a small version of almost every half-yearly, every two months.
Each version introduces some new features. What I want to introduce today is a new feature introduced from the jquery 1.5.0 Release----Deferred object.
This feature is important and the future will be the core approach to jquery, which has revolutionized how Ajax is used in jquery. To achieve this, all of jquery's AJAX code has been rewritten. However, it is more abstract, beginners are difficult to master, online tutorials are not many. So, I put my own study notes out, hope to be useful to everyone.
This is not a beginner's tutorial and is intended for developers who already have experience with jquery. If you want to understand the basic use of jquery, read the jquery design ideas I wrote and the jquery best practices.
======================================
A detailed description of the deferred object of jquery
Nanyi
First, what is the deferred object?
In the process of developing a website, we often encounter some long-time JavaScript operations. Where there are asynchronous operations (such as AJAX reading server data) and synchronous operations (such as traversing a large array), they are not immediately able to get results.
It is common practice to specify a callback function (callback) for them. That is, which functions should be called as soon as they run to completion.
However, in terms of callback functions, jquery has a very weak function. To change this, the jquery development team designed the deferred object.
simply put, the deferred object is the callback function solution for jquery. in English, defer means "delay", so the meaning of the deferred object is "delay" to some point in the future to execute.
It solves the problem of how to handle time-consuming operations, provides better control over those operations, and a unified programming interface. Its main function can be attributed to four points. Let's go through the sample code and learn it one step at a.
Second, the Ajax operation of the chain-style notation
First, look back at the traditional writing of jquery's Ajax operations:
$.ajax ({
URL: "Test.html",
Success:function () {alert ("Haha, success!") "); },
Error:function () {alert ("Error! "); }
});
(Run code example 1)
In the above code, $.AJAX () accepts an object parameter that contains two methods: The Success method specifies the callback function after the operation succeeds, and the error method specifies the callback function after the operation failed.
After the $.ajax () operation is complete, if you are using a jquery that is less than 1.5.0, you are returning the XHR object, you cannot do the chained operation, and if you are above the 1.5.0 version, the deferred object is returned, and you can chain-operate.
Now, the new wording is this:
$.ajax ("test.html")
. Done (function () {alert ("Haha, success! "); })
. Fail (function () {alert ("Error! "); });
(Run code example 2)
As you can see, done () is equivalent to the success method, and fail () is equivalent to the error method. After using chained notation, the readability of the code is greatly improved.
Iii. specifying multiple callback functions for the same operation
One of the great benefits of deferred objects is that it allows you to freely add multiple callback functions.
As an example of the above code, if the Ajax operation succeeds, in addition to the original callback function, I would like to run a callback function, how to do?
It's very simple, just add it to the back of the line.
$.ajax ("test.html")
. Done (function () {alert ("Haha, success! ");} )
. Fail (function () {alert ("Error! "); } )
. Done (function () {alert ("Second callback function!) ");} );
(Run code example 3)
The callback function can add any number of them, which are executed in the order in which they are added.
Iv. specifying callback functions for multiple operations
Another great benefit of the deferred object is that it allows you to specify a callback function for multiple events, which is not done in traditional notation.
Take a look at the following code, which uses a new method $.when ():
$.when ($.ajax ("test1.html"), $.ajax ("test2.html"))
. Done (function () {alert ("Haha, success! "); })
. Fail (function () {alert ("Error! "); });
(Run code example 4)
This code means that you perform two operations $.ajax ("test1.html") and $.ajax ("test2.html"), and if all succeeds, run the callback function specified by done (); fail () if one fails or fails The specified callback function.
V. Normal operation callback function interface (upper)
The biggest advantage of the deferred object is that it extends this set of callback function interfaces from Ajax operations to all operations. That is, any operation----whether it is an AJAX operation or a local operation, whether it is an asynchronous operation or a synchronous operation----can use various methods of the deferred object to specify a callback function.
Let's look at a concrete example. Suppose there is a time-consuming operation, wait:
var wait = function () {
var tasks = function () {
Alert ("Execution finished!") ");
};
SetTimeout (tasks,5000);
};
We specify a callback function for it, what should we do?
Naturally, you will think that you can use $.when ():
$.when (Wait ())
. Done (function () {alert ("Haha, success! "); })
. Fail (function () {alert ("Error! "); });
(Run code example 5)
However, by doing so, the done () method executes immediately, not the function of the callback function. The reason is that the $.when () parameter can only be a deferred object, so you must overwrite wait ():
var DTD = $. Deferred (); Create a new Deferred object
var wait = function (DTD) {
var tasks = function () {
Alert ("Execution finished!") ");
dtd.resolve (); Changing the execution state of a deferred object
};
SetTimeout (tasks,5000);
return DTD;
};
The wait () function now returns the deferred object, which can be added as a chained operation.
$.when (Wait (DTD))
. Done (function () {alert ("Haha, success! "); })
. Fail (function () {alert ("Error! "); });
(Run code example 6)
When the wait () function finishes running, the callback function specified by the done () method is automatically run.
Vi. Deferred.resolve () method and Deferred.reject () method
If you look closely, you will find in the wait () function above, there is another place I did not explain. So what is the role of Dtd.resolve ()?
To be clear about this problem, a new concept of "execution state" should be introduced. jquery states that the deferred object has three execution states----incomplete, completed, and failed. If the execution state is "completed" (resolved), the deferred object immediately invokes the callback function specified by the done () method, or the callback function specified by the fail () method if the execution state is "failed", or if the execution state is "not completed", continue waiting, or call the callback function specified by the progress () method (the jQuery1.7 version is added).
In the previous part of the Ajax operation, the deferred object automatically changes its execution state based on the returned results, but in the wait () function, the execution state must be manually specified by the programmer. Dtd.resolve () triggers the Done () method by changing the execution state of the DTD object from "unfinished" to "completed".
Similarly, there is a deferred.reject () method that triggers the Fail () method by changing the execution state of the DTD object from "unfinished" to "failed".
var DTD = $. Deferred (); Create a new Deferred object
var wait = function (DTD) {
var tasks = function () {
Alert ("Execution finished!") ");
Dtd.reject (); Changing the execution state of a deferred object
};
SetTimeout (tasks,5000);
return DTD;
};
$.when (Wait (DTD))
. Done (function () {alert ("Haha, success! "); })
. Fail (function () {alert ("Error! "); });
(Run code example 7)
Vii. deferred.promise () method
There is still a problem with the above notation. That is, the DTD is a global object, so its execution state can change from the outside.
Take a look at the following code:
var DTD = $. Deferred (); Create a new Deferred object
var wait = function (DTD) {
var tasks = function () {
Alert ("Execution finished!") ");
Dtd.resolve (); Changing the execution state of a deferred object
};
SetTimeout (tasks,5000);
return DTD;
};
$.when (Wait (DTD))
. Done (function () {alert ("Haha, success! "); })
. Fail (function () {alert ("Error! "); });
Dtd.resolve ();
(Run code example 8)
I added a line dtd.resolve () at the end of the code, which changed the execution state of the DTD object, causing the done () method to execute immediately, jumping out of "haha, success!" "The Prompt box, wait 5 seconds and then jump out" execution finished! "In the Prompt box.
To avoid this situation, jquery provides the Deferred.promise () method. It does this by returning another deferred object on the original deferred object, which only opens methods (such as the Done () method and the Fail () method) that are independent of the change execution state, masking methods related to changing the execution state (such as resolve () Method and The Reject () method) so that the execution state cannot be changed.
Take a look at the following code:
var DTD = $. Deferred (); Create a new Deferred object
var wait = function (DTD) {
var tasks = function () {
Alert ("Execution finished!") ");
Dtd.resolve (); Changing the execution state of a deferred object
};
SetTimeout (tasks,5000);
return Dtd.promise (); Returns the Promise Object
};
var d = Wait (DTD); Create a new D object and manipulate the object instead
$.when (d)
. Done (function () {alert ("Haha, success! "); })
. Fail (function () {alert ("Error! "); });
D.resolve (); At this point, the statement is invalid.
(Run code example 9)
In the above code, the Wait () function returns the Promise object. We then bind the callback function above the object, not the original deferred object. The benefit is that you cannot change the execution state of the object, but you can only manipulate the original deferred object if you want to change the execution state.
However, it is better to use the ALLENM to change the DTD object into an internal object of the wait () function.
var wait = function (DTD) {
var DTD = $. Deferred (); Inside the function, create a new deferred object
var tasks = function () {
Alert ("Execution finished!") ");
Dtd.resolve (); Changing the execution state of a deferred object
};
SetTimeout (tasks,5000);
return Dtd.promise (); Returns the Promise Object
};
$.when (Wait ())
. Done (function () {alert ("Haha, success! "); })
. Fail (function () {alert ("Error! "); });
(Run code example 10)
Eight, normal operation callback function interface (middle)
Another way to prevent the execution state from being externally altered is to use the constructor $ for the deferred object. Deferred ().
At this point, the wait function remains the same, and we pass it directly to $. Deferred ():
$. Deferred (Wait)
. Done (function () {alert ("Haha, success! "); })
. Fail (function () {alert ("Error! "); });
(Run code example 11)
jquery rules, $. Deferred () can accept a function name (note, which is the name of the letter) as a parameter, $. The Deferred object generated by Deferred () will be used as the default parameter for this function.
Nine, normal operation of the callback function interface (bottom)
In addition to the above two methods, we can also deploy the deferred interface directly on the wait object.
var DTD = $. Deferred (); Generating deferred objects
var wait = function (DTD) {
var tasks = function () {
Alert ("Execution finished!") ");
Dtd.resolve (); Changing the execution state of a deferred object
};
SetTimeout (tasks,5000);
};
Dtd.promise (wait);
Wait.done (function () {alert ("Haha, success!") "); })
. Fail (function () {alert ("Error! "); });
Wait (DTD);
(Run code example 12)
The key here is the dtd.promise (wait) line, which is the role of deploying the deferred interface on the wait object. Because of this line, you can call done () and fail () directly on wait.
X. Summary: Methods of deferred objects
There are several ways to deferred objects, and here's a summary:
(1) $. Deferred () generates a Deferred object.
(2) Deferred.done () specifies the callback function when the operation succeeds
(3) Deferred.fail () specifies the callback function when the operation fails
(4) Deferred.promise () when there is no parameter, a new deferred object is returned, and the running state of the object cannot be changed; When the parameter is accepted, the role is to deploy the deferred interface on the Parameter object.
(5) Deferred.resolve () manually changes the running state of the deferred object to "completed", triggering the Done () method immediately.
(6) Deferred.reject () This method is the opposite of Deferred.resolve (), which, after invocation, changes the running state of the deferred object to "failed", triggering the Fail () method immediately.
(7) $.when () specifies a callback function for multiple operations.
In addition to these methods, the deferred object has two important methods that are not covered in the tutorial above.
(8) Deferred.then ()
Sometimes to save time, you can write the done () and fail () together, and this is the then () method.
$.when ($.ajax ("/main.php"))
. Then (Successfunc, Failurefunc);
If then () has two parameters, then the first parameter is the callback function of the Done () method, and the second parameter is the callback method of the Fail () method. If then () has only one parameter, then it is equivalent to done ().
(9) Deferred.always ()
This method is also used to specify the callback function, which is the function, regardless of whether the call is Deferred.resolve () or Deferred.reject (), and finally always executed.
$.ajax ("test.html")
. Always (function () {alert ("Executed! ");} );
(acknowledgements: After the first draft of this article was published, Allenm's letter stated that the original understanding of promise () was wrong. Now the second draft is revised according to his article, I would like to express my heartfelt thanks. )
Finish
"Reprint" http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html
A detailed description of the deferred object of jquery