Please continue with the last lesson.
$. In the Deferred () method, there are two objects, one is the Deferred object and one is the Promise object.
The Promise object has several methods: State,always,then,promise,pipe,done,fail,progress.
The deferred object is in addition to all the methods of the Promise object (through Jquery.extend (obj, Promise), all methods of the Promise object are copied to the deferred object), and there are three others: Resolve,reject , notify.
What is the difference between them? Let's look at an example first;
function A () {
var cb = $. Deferred ();
SetTimeout (function () {
Cb.resolve ();
},1000)
return CB;
}
var NEWCB = a ();
Newcb.done (function () {
Alert ("Success");
}). Fail (function () {
Alert ("Failed")
});
The above code, after one second, will pop up successfully. However, if we add newcb.reject () at the end of the code, and only the failure will pop up, the success will not pop up (because the Reject method is executed first, and the implementation of the deferred object is once, so the resolve call does not perform the method of the popup success). As we can see above, we can change the state of the lingering object in the code (which would have been successful, but failed).
Workaround: We return cb.promise () when we return to the A method. At this point, the delay object CB will not change the state. You add cb.reject to the end of the code (because the Promise object has no Resolve,reject,notify method, only the deferred object has).
From the above, deferred object can change state, promise object cannot change state.
Cb.promise () method source code is:
Promise:function (obj) {
return obj! = null? Jquery.extend (obj, Promise): promise;
}
The Promise object is returned.
Next, let's look at how the state of the lingering object changes:
There are three states of lingering objects: the default is pending. Success is resolved, and failure is rejected.
The source code is changed in this way:
var tuples = [
["Resolve", "done", Jquery.callbacks ("Once Memory"), "resolved"],
["Reject", "fail", Jquery.callbacks ("Once Memory"), "rejected"],
["Notify", "Progress", Jquery.callbacks ("Memory")]
],
state = "Pending",
Jquery.each (tuples, function (i, tuple) {
var list = tuple[2],
Statestring = tuple[3]; //resolved,rejected
promise[tuple[1]] = List.add; //After adding the following add, Promise = {"Done": [Functon () {},fail.disable,progress.lock], "fail": [Functon () {},done.disable, Progress.lock]}
if (statestring) { //enter into an if statement, the resolved state and rejected state can be entered into the IF statement
List.add (function () {
state = statestring;
TUPLES[0][2] = Jquery.callbacks ("Once Memory")
}, tuples[i ^ 1 [2].disable, tuples[2] [2].lock]; //[reject_list | resolve_list].disable; progress_list.lock
//Add three methods to the list. The first method is to change the state. Because the success state and the failure state can only occur one time, and only once, the following two methods are to implement a change that cannot be made to the state. The tuples[2 [2].lock, in fact, is jquery.callbacks ("Memory"). Lock, which means that the fire method in progress is invalid and no longer fires. The second method, disable, is to disable all functions of the callback. I=0 or 1, when i=0, represents a successful state, tuples[1][2]= jquery.callbacks ("Once Memory"), at which point the failed state (fail) is not available for all functions. When I=1 represents a failed state, then tuples[0][2] all functions that represent a successful state (done) are not available. This means that when resolve is executed, it represents a state of success, when reject (the state becomes a failure) is no longer triggered.
A simpler understanding is that when the resolve is called, the state becomes resolved, and then the reject,fail of the failed state does not execute any of the methods. And the in-progress fire Method (notify method) cannot be executed, but the method it progress adds can be executed (if the Notfy method is called before the Resolve method).
}
.....
}
The Always method is also used to add methods, such as: Cb.always (function () {}), but the method means that, whether it is a success or failure, its methods will be executed.
Always:function () {
Deferred.done (arguments). Fail (arguments);
return this;
},
Then method: Cb.then (function () {success},function () {failed},function () {in progress}); You can add a success, failure, and three callback methods in progress.
then:function (Fndone, Fnfail, fnprogress) {
var fns = arguments;
return jquery.deferred (function (newdefer) { //Returns a deferred object promise that cannot change state, in the callback method, the incoming Newdefer is a new deferred object deferred
Jquery.each (tuples, function (i, tuple) { //First loop, i=0,tuple=["resolve", "done", Jquery.callbacks ("Once Memory ")," resolved "]
var action = tuple[0],//resolve
fn = jquery.isfunction (fns[i]) && fns[i];
deferred[tuple[1]] (function () { //Call the old deferred object deferred the Done method, that is, Deferred.done (function () {}), so the old deferred When resolve is called, this callback method is executed, and the callback method executes the new deferred object Newdefer The callback method that is added through done
var returned = fn && fn.apply (this, arguments); //execute then (pipe) Add method, here is function () {success}
If (returned && jquery.isfunction (returned.promise)) { //If the return value is a deferred object, enter the IF statement
returned.promise () //If a deferred object returned is returned, it is promise and then mapped with a hash to the new deferred object. Promise resolve a call, the resolve of Newdefer is executed, and the method added by done Newdefer is executed.
. Done (newdefer.resolve)
. Fail (newdefer.reject)
. Progress (newdefer.notify);
}
else { //If a string is returned, Newdefer[resolvewith] (execution context, [return value]), The Resolvewith method of the deferred object is the List.firewith method, which executes the method Newdefer.done added FN. and pass the parameter value (returned string) into this callback method FN.
newdefer[action + ' with '] (this = = = Promise? Newdefer.promise (): This, fn? [returned]: arguments);
}
});
});
FNS = null;
}). Promise ();
},
Promise.pipe = Promise.then; The //pipe method is the then method.
Use of the pipe method for lingering objects:
var cb = $. Deferred ();
SetTimeout (function () {
Cb.resolve ("Hi"); //This is the method that triggered the Cb.done addition, but the method that triggered the Newcb.done addition
},1000)
The var NEWCB = cb.pipe (function () { //pipe method means pipeline, meaning that the lingering object can be extended. This expands the CB so that the first parameter is followed by a Chaojidan string. So the new deferred object NEWCB is added after the first argument Chaojidan
return arguments[0] + "Chaojidan";
})
Newcb.done (function () {
Alert (arguments[0]); //This will pop up Hi Chaojidan. Because NEWCB is a CB extension, that is, inherited, so cb.resolve will trigger Newcb.done added method.
})
Above this method then source comparison around, to the front-end development does not help, is some logical processing, can be ignored. And this method uses less, know how to use, know the method is used to do what is OK.
Come on!
jquery Source parsing: jquery Deferred object deferred (tool method) 2