5. Asynchronous Queue Deferred 
5.1 Overview 
An asynchronous queue is a chained object that enhances the management and invocation of callback functions to handle asynchronous tasks. 
There are three states of asynchronous queues: initialization (unresolved), success (resolved), failure (rejected). 
Which callback functions to perform depend on the state. 
After the status becomes successful (resolved) or failed (rejected), it remains unchanged. 
The binding of a callback function can be either synchronous or asynchronous, that is, it can be bound at any time. 
(The binding registration additions in this section have the same meaning) 
5.2 Key Methods 
Take a look at jquery first. The key method in Deferred () 
Classification 
Method 
Description 
Increase 
Deferred.done () 
Add Success callback function 
Call immediately if the status is successful (resolved) 
Deferred.fail () 
To increase the failed callback function 
Call immediately if the status is failed (rejected) 
Deferred.then () 
Increase the success callback function and the failure callback function into the respective queues 
Convenient method, two parameters can be array or null 
Call the success callback function immediately when the status is successful (resolved) 
Call the failed callback function immediately when the status is failed (rejected) 
Deferred.always () 
Increase the callback function while adding to the success queue and the failed queue 
Call callback function immediately if state is determined (either successful or unsuccessful) 
Perform 
Deferred.resolve () 
Call Successful callback function queue 
Implemented by calling Deferred.resolvewith () 
Deferred.resolvewith () 
Executes a successful callback function using the specified context and parameters 
Deferred.reject () 
Call failed callback function queue 
Implemented by calling Deferred.rejectwith () 
Deferred.rejectwith () 
Executes a failed callback function queue with the specified context and parameters 
Other 
Deferred.isrejected () 
Determine whether the state is successful (resolved) 
Deferred.isresolved () 
Determine whether the state is a failure (rejected) 
Deferred.pipe () 
Call the incoming Success filter function or the failure filter function before calling the callback function and use the return value of the filter function as the parameter of the callback function 
Finally returns a read-only view (Invoke promise implementation) 
Deferred.promise () 
Returns a read-only view of deferred 
Next will be jquery._deferred and jquery.deferred The source code detailed analysis. 
 
 
5.3 jquery._deferred 
 
 
  
  Copy Code code as follows: 
 
 
  
 
 
Local variables 
 
Resources: 
 
Official website Document http://api.jquery.com/category/deferred-object/ 
 
Deferred mechanism http://www.cnblogs.com/fjzhou/archive/2011/05/30/jquery-source-3.html 
 
Using the deferred object in jquery 1.5 http://developer.51cto.com/art/201103/248638.htm 
 
Take a magnifying glass to see promise http://www.cnblogs.com/sanshi/archive/2011/03/11/1981789.html 
 
promises/a Http://wiki.commonjs.org/wiki/Promises/A 
 
var//Promise methods 
 
Note that there are no following methods: Resolvewith resolve Rejectwith reject pipe when cancel 
 
That is, the call to resolve reject Cancel is not allowed 
 
Promisemethods = "Done fail isresolved isrejected promise then always pipe". Split (""), 
 
Static reference to Slice 
 
Static reference slice method, borrow chicken eggs 
 
slicedeferred = [].slice; 
 
_deferred: 
 
_deferred:function () { 
 
var//Callbacks List 
 
Array of callback functions (not translated here as queues to avoid conceptual confusion) 
 
Callbacks = [], 
 
stored [context, args] 
 
Stores context, parameters, and can also identify whether completion is performed (fired is complete) 
 
"Finish" here means that the "existing" function in the callback function array has been completed; 
 
However, you can invoke the done add callback function again, and the fired will be reset to 0 when added 
 
Fired, 
 
To avoid firing when already doing 
 
If the trigger is already executing, avoid triggering again 
 
Firing, 
 
Flag to know if the deferred has been cancelled 
 
Identifies whether the asynchronous queue has been canceled, and the call to the done resolve Resolvewith will be ignored after cancellation 
 
Cancelled, 
 
Asynchronous queue definition (this is the principal, the top local variable is referenced by the closure) 
 
The deferred itself 
 
Deferred = { 
 
Done (F1, F2, ...) 
 
Adds a successful callback function called immediately when the status is successful (resolved) 
 
Done:function () { 
 
If canceled, this call is ignored 
 
if (!cancelled) { 
 
Define the benefits of the local variables used in the code blocks at the beginning of the code block: 
 
1. Declare variables to increase the readability of the Code; 
 
2. Share variables, improve performance 
 
Note: Many years of experience in Java, to develop a global variable at the beginning, the temporary variable with the custom, it seems that JavaScript somewhat different 
 
var args = arguments,//callback function array 
 
I,//traversal variable 
 
Length,//callback function array lengths 
 
Elem,//single callback function 
 
Type,//Elem types 
 
_fired; For temporary backups fired (context and parameters are stored in fired) 
 
If completion is performed (that is, the context and parameters are preserved in fired) 
 
Then the backup context and parameters are _fired and the fired is set to 0 
 
if (fired) { 
 
_fired = fired; 
 
Fired = 0; 
 
} 
 
Add a function in arguments to an array of callback functions 
 
for (i = 0, length = args.length i < length; i++) { 
 
Elem = args[I]; 
 
Type = Jquery.type (elem); 
 
If it is an array, the recursive call 
 
if (type = = "Array") { 
 
Forces the specified context to be deferred, and the individual does not think it is necessary to specify the context, because the default context is deferred 
 
Deferred.done.apply (deferred, elem); 
 
else if (type = = "function") { 
 
Callbacks.push (Elem); 
 
} 
 
} 
 
If executed (_fired indicates that the state of the deferred is OK), the newly added function is executed immediately 
 
Use the context contexts and parameters specified previously args 
 
if (_fired) { 
 
Deferred.resolvewith (_fired[0], _fired[1]); 
 
} 
 
} 
 
return this; 
 
}, 
 
Resolve with given context and args 
 
execution, using the specified context and parameters 
 
Resolvewith:function (context, args) { 
 
All of the following conditions are true: No cancellation, no execution, no completion 
 
If it has been canceled or completed or is executing, this call is ignored 
 
if (!cancelled &&!fired &&!firing) { 
 
Make sure args are available (#8421) 
 
Make sure args is available, a common technique for avoiding null and undefined causing referenceerror 
 
args = args | | []; 
 
During execution, change firing to 1 
 
firing = 1; 
 
try { 
 
Techniques for traversing a dynamic array 
 
while (callbacks[0]) { 
 
Note that the specified context is used instead of this 
 
Callbacks.shift (). Apply (context, args); 
 
} 
 
} 
 
JavaScript support try/catch/finally 
 
finally { 
 
Fired = [context, args]; 
 
firing = 0; 
 
} 
 
} 
 
return this; 
 
}, 
 
Resolve with the as context and given arguments 
 
Set the status to Resolved 
 
The setting of the understanding is not accurate, because whether resolved, is called isresolved judge firing, fired state. 
 
Can be understood as executing 
 
Resolve:function () { 
 
Deferred.resolvewith (this, arguments); 
 
return this; 
 
}, 
 
Has this deferred been resolved? 
 
Have you executed (or resolved)? 
 
Deemed to have been performed/resolved after execution or completion 
 
"Already" may not be accurate because it is considered to have been performed during execution 
 
Isresolved:function () { 
 
Running in 
 
Or 
 
Finished running (that is, fired is not empty/0) 
 
Return!! (Firing | | fired); 
 
}, 
 
Cancel 
 
Canceling an asynchronous queue 
 
Set tag bit, empty function queue 
 
Cancel:function () { 
 
Cancelled = 1; 
 
callbacks = []; 
 
return this; 
 
} 
 
}; 
 
return deferred; 
 
} 
 
 
 
5.4 jquery.deferred 
 
 
  
  Copy Code code as follows: 
 
 
  
 
 
Full fledged deferred (two callbacks list) 
 
Create a complete asynchronous queue (contains two callback function arrays) 
 
There are three states of asynchronous queues: initialization (unresolved), success (resolved), failure (rejected). 
 
Which callback functions to perform depend on the state. 
 
After the status becomes successful (resolved) or failed (rejected), it remains unchanged. 
 
Deferred:function (func) { 
 
_deferred has no success or failure status, there are four states: initialization, execution, execution completed, canceled 
 
For code reuse, the interior first implements a _deferred 
 
Faildeferred is referenced by a closure package 
 
var deferred = jquery._deferred (), 
 
faildeferred = jquery._deferred (), 
 
Promise 
 
Add errordeferred methods, then and promise 
 
Jquery.extend (Deferred, { 
 
Increase the success callback function and the failure callback function into the respective queues 
 
Convenient method, two parameters can be array or null 
 
Call the success callback function immediately when the status is successful (resolved) 
 
Call the failed callback function immediately when the status is failed (rejected) 
 
Then:function (Donecallbacks, failcallbacks) { 
 
Context has a toggle here: Although the done return is deferred, fail points to faildeferred.done, execution fail is the context changes to faildeferred 
 
The simple point is: 
 
Add a callback function to the deferred when the call is done donecallbacks 
 
Add a callback function to faildeferred when calling fail Failcallbacks 
 
So after this line of expression is executed, the faildeferred is returned. 
 
Deferred.done (donecallbacks). Fail (failcallbacks); 
 
Force return deferred 
 
return this; 
 
}, 
 
Register a callback function, either resolved or rejected will be invoked. 
 
In fact, is to put the incoming function (array), while adding to deferred and faildeferred 
 
is not stored in a separate function array, as I imagined. 
 
Always:function () { 
 
The done context is set to the Deferred,fail context set to this 
 
Are the done and fail contexts inconsistent? Consistent! Here this is equal to deferred 
 
But how do you explain this setting context? What's the difference with then's implementation? 
 
Fail points to fail pointing to Faildeferred.done, the default context is the faildeferred,faildeferred callback function array callbacks is referenced by the closure. 
 
Although the context of the Faildeferred.done method is set to deferred, it does not affect faildeferred.done execution. 
 
At the end of the Faildeferred.done, replace this with the deferred and implement a chained call, 
 
That is, no context is lost in the call procedure this, you can continue to call other methods without causing this confusion 
 
From the grammatical, always to achieve the effect and then to achieve the same effect 
 
Therefore, this line of code can be rewritten as two lines (similar to then implementations), and the effect is equivalent: 
 
Deferred.done (arguments). Fail (arguments); 
 
Returnr this; 
 
Return deferred.done.apply (deferred, arguments). fail.apply (this, arguments); 
 
}, 
 
To increase the failed callback function 
 
Call immediately if the status is failed (rejected) 
 
Fail:failDeferred.done, 
 
Executes a failed callback function queue with the specified context and parameters 
 
Implemented by calling Faildeferred.rejectwith () 
 
RejectWith:failDeferred.resolveWith, 
 
Call failed callback function queue 
 
Implemented by calling Faildeferred.resolve () 
 
Reject:failDeferred.resolve, 
 
Determine whether the state is successful (resolved) 
 
IsRejected:failDeferred.isResolved, 
 
Call the incoming Success filter function or the failure filter function before calling the callback function and use the return value of the filter function as the parameter of the callback function 
 
Finally returns a read-only view (Invoke promise implementation) 
 
Fndone is called when the state is successful (resolved) 
 
Fnfail is called when the state is failed (rejected) 
 
For other explanations: 
 
1. Some articles are translated as "piping mechanisms", literally unable to understand what is meant to be expressed, so at least inaccurate 
 
2. Error understanding: The so-called pipe, just put the incoming fndone and fnfail into the array head of the success queue and the failure queue 
 
Pipe:function (Fndone, Fnfail) { 
 
Return jquery.deferred (function (newdefer) { 
 
Jquery.each ({ 
 
Done: [Fndone, ' resolve '],//done in the following text will point to Deferred.done 
 
Fail: [Fnfail, "reject"] 
 
}, function (handler, data) { 
 
var fn = data[0], 
 
Action = data[1], 
 
returned; 
 
if (Jquery.isfunction (FN)) { 
 
deferred[Handler] (function () { 
 
returned = Fn.apply (this, arguments); 
 
if (returned && jquery.isfunction (returned.promise)) { 
 
Returned.promise (). Then (Newdefer.resolve, Newdefer.reject); 
 
} else { 
 
newdefer[Action] (returned); 
 
} 
 
}); 
 
} else { 
 
deferred[Handler] (newdefer[action)); 
 
} 
 
}); 
 
}). Promise (); 
 
}, 
 
Get a promise to this deferred 
 
If obj is provided, the promise aspect are added to the object 
 
Returns an incomplete deferred interface, without resolve and reject, that is, the state of the deferred object cannot be modified. 
 
This is to not allow the external function to trigger the callback function early, and can be considered as a read-only view. 
 
// 
 
For example, $.ajax does not return XMLHttpRequest after version 1.5, but instead returns an object that encapsulates the XMLHttpRequest and deferred object interfaces. 
 
The deferred part is promise () so that the external function does not call resolve and reject, preventing the callback function from being triggered before the Ajax completes. 
 
Leave the invocation rights of these two functions to the internal Ajax. 
 
Promise:function (obj) { 
 
if (obj = = null) { 
 
The promise is actually performed only once, and the results of the first execution are stored in the promise variable 
 
if (Promise) { 
 
return promise; 
 
} 
 
Promise = obj = {}; 
 
} 
 
var i = promisemethods.length; 
 
Another kind of loop traversal method 
 
I am accustomed to using: 
 
for (i = 0; i < len; i++) or for (i = len-1 i >=0; i--) or for (i = len; i--;) 
 
jquery is a treasure! 
 
while (i--) { 
 
obj[Promisemethods[i]] = deferred[Promisemethods[i]]; 
 
} 
 
return obj; 
 
} 
 
}); 
 
Make sure only one callback list would be used 
 
Failure with column cancellation method is performed after successful queue execution completes 
 
The cancellation method for a successful queue is performed after the failure queue execution completes 
 
Make sure that only one function queue is executed, that is, either the successful queue is executed or the failed queue is executed; 
 
That is, the state can only be or succeeds, or fails, without cross calls 
 
The canceled properties of deferred and faildeferred can only be referenced through closures, so don't worry about state, context clutter 
 
Deferred.done (Faildeferred.cancel). Fail (deferred.cancel); 
 
Unexpose Cancel 
 
Hide Cancel interface, that is, the successful function queue cannot be canceled externally 
 
Delete Deferred.cancel; 
 
Call given Func if any 
 
Execute the incoming Func function 
 
if (func) { 
 
Func.call (deferred, deferred); 
 
} 
 
return deferred; 
 
} 
 
 
 
5.5 Jquery.when 
 
 
  
  Copy Code code as follows: 
 
 
  
 
 
Deferred Helper 
 
Asynchronous Queue Tool Functions 
 
Firstparam: One or more deferred objects or JavaScript generic objects 
 
When:function (Firstparam) { 
 
var args = arguments, 
 
i = 0, 
 
Length = Args.length, 
 
Count = length, 
 
If the arguments.length equals 1 and Firstparam is deferred, then Deferred=firstparam 
 
Otherwise, a new deferred object is created (if Arguments.length equals 0 or greater than 1, a new deferred object is created) 
 
by Jquery.isfunction (firstparam.promise) Simple to determine whether the deferred object 
 
deferred = length <= 1 && firstparam && jquery.isfunction (firstparam.promise)? 
 
Firstparam: 
 
Jquery.deferred (); 
 
Constructed success (resolve) callback function 
 
function Resolvefunc (i) { 
 
return function (value) { 
 
If the incoming argument is greater than one, the incoming argument is converted to a true array (arguments no slice method, borrow chicken eggs) 
 
args[i] = arguments.length > 1? Slicedeferred.call (arguments, 0): value; 
 
if (! (--count)) { 
 
Strange bug in FF4: 
 
Values changed onto the arguments object sometimes end up as undefined values 
 
Outside the $.when method. Cloning the object into a fresh array solves the issue 
 
Execute successfully callback function queue, context forced to incoming first deferred object 
 
Deferred.resolvewith (deferred, Slicedeferred.call (args, 0)); 
 
} 
 
}; 
 
} 
 
If the argument is more than one 
 
if (length > 1) { 
 
for (; i < length; i++) { 
 
Simple to judge whether it is a deferred object, call. Promise (). Then (), or ignore 
 
if (args[i] && jquery.isfunction (args[i].promise)) { 
 
Increase the success callback function and the failure callback function into the respective queues 
 
args[i].promise (). Then (Resolvefunc (i), deferred.reject); 
 
} else { 
 
Counter, which indicates that the discovery is not a deferred object, but a normal JavaScript object 
 
--count; 
 
} 
 
} 
 
The counter is 0 o'clock, indicating that the incoming arguments are not deferred objects 
 
Execute successfully callback function queue, context forced to incoming first deferred object 
 
if (!count) { 
 
Deferred.resolvewith (deferred, args); 
 
} 
 
Deferred!== Firstparam, that is, deferred for the newly created deferred object 
 
Length = = 0 
 
else if (deferred!== firstparam) { 
 
Execution successfully callback function queue, context forced for newly created deferred object 
 
Deferred.resolvewith (deferred, length?) [Firstparam]: []); 
 
} 
 
Returns the read-only view of the first deferred or newly created deferred object passed in 
 
return Deferred.promise (); 
 
} 
 
 
 
 
5.6 Deferred Application 
L Jquery.ajax () 
N TODO 
5.7 Skills that can be learned 
L Closure 
 
 
  
  Copy Code code as follows: 
 
 
  
 
  
  
function A () { 
  
var guid = 1; 
  
return function () { 
  
return guid++; 
  
} 
  
} 
  
var defer = a (); 
  
Console.info (Defer ()); 1 
  
Console.info (Defer ()); 2 
  
Console.info (Defer ()); 3 
  
Console.info (Defer ()); 4 
  
 
 
 
  
• Common techniques to avoid null and undefined causing referenceerror 
args = args | | []; 
L The technique of traversing a dynamic array 
while (callbacks[0]) { 
Callbacks.shift (). Apply (context, args); 
} 
L try/catch/finally Implementation error handling 
Grammar 
Description 
try { 
Trystatements 
} catch (Exception) { 
Catchstatements 
finally { 
Finallystatements 
} 
Trystatements 
Required option. 
The statement that the error may occur. 
exception 
Required option. Any variable name. 
The initialization value of the exception is the value of the error thrown out. 
Catchstatements 
Options available. 
A statement that handles errors that occur in the associated trystatement. 
Finallystatements 
Options available. 
A statement that executes unconditionally after all other processes occur. 
L-Chained object: Implement chained call by returning this 
Method 
return value 
Done 
This (ie deferred) 
Resolvewith 
This (ie deferred) 
Resolve 
This (ie deferred) 
Cancel 
This (ie deferred) 
L Code Multiplexing $.each 
Jquery.each ({ 
Done: [Fndone, ' resolve '],//done in the following text will point to Deferred.done 
Fail: [Fnfail, "reject"] 
}, function (handler, data) { 
Common code Reuse 
}); 
5.8 Follow-up 
Application of L-deferred in jquery 
Self-defined application of L deferred