JQuery source code analysis-05 introduction to asynchronous queue Deferred

Source: Internet
Author: User

5. asynchronous queue Deferred
5.1 Overview
Asynchronous queue is a chained object that enhances the management and calling of callback functions for processing asynchronous tasks.
Asynchronous queues have three statuses: initialization (unresolved), success (resolved), and failure (rejected ).
Which callback functions are executed depends on the status.
After the status changes to resolved or failed, it remains unchanged.
The callback function can be bound synchronously or asynchronously, that is, it can be bound at any time.
(The addition of binding and registration in this section has the same meaning)
5.2 Key Methods
Let's take a look at the key methods in jQuery. Deferred ().
Category
Method
Description
Add
Deferred. done ()
Added a successful callback function.
Call immediately when the status is resolved
Deferred. fail ()
Added the failed callback function.
Call immediately when the status is rejected
Deferred. then ()
Add the success callback function and failure callback function to their respective queues.
Convenient Method. Two parameters can be array or null.
Call the success callback function immediately when the status is resolved.
Call the failed callback function immediately when the status is rejected.
Deferred. always ()
Add the callback function and add it to the success queue and failure queue at the same time.
Call the callback function immediately when the status is determined (whether successful or failed ).
Run
Deferred. resolve ()
Callback Function queue
By calling deferred. resolveWith ()
Deferred. resolveWith ()
The callback function is successfully executed using the specified context and parameter.
Deferred. reject ()
Call failure callback function queue
By calling deferred. rejectWith ()
Deferred. rejectWith ()
Callback Function queue with the specified context and parameter execution failure
Others
Deferred. isRejected ()
Check whether the status is successful (resolved)
Deferred. isResolved ()
Check whether the status is failed (rejected)
Deferred. pipe ()
Before calling the callback function, call the input success filter function or failure filter function, and use the return value of the filter function as the callback function parameter.
Finally, a read-only view is returned (implemented by calling promise)
Deferred. promise ()
Returns the read-only view of deferred.
The following describes the source code of jQuery. _ Deferred and jQuery. Deferred.


5.3 jQuery. _ Deferred
Copy codeThe Code is as follows:
Local variable
// Reference:
// Official documentation http://api.jquery.com/category/deferred-object/
// Deferred mechanism http://www.cnblogs.com/fjzhou/archive/2011/05/30/jquery-source-3.html
// Use the deferred object http://developer.51cto.com/art/201103/248638.htm in jQuery 1.5
// Watch Promise http://www.cnblogs.com/sanshi/archive/2011/03/11/1981789.html with a magnifier
// Promises/A http://wiki.commonjs.org/wiki/Promises/A
Var // Promise methods
// Note that the following method is not available: resolveWith resolve rejectWith reject pipe when cancel
// You are not allowed to call resolve reject cancel.
PromiseMethods = "done fail isResolved isRejected promise then always pipe". split (""),
// Static reference to slice
// Reference the slice Method statically.
SliceDeferred = []. slice;
_ Deferred:
_ Deferred: function (){
Var // callbacks list
// Callback Function Array (this is not translated as a queue to avoid conceptual confusion)
Callbacks = [],
// Stored [context, args]
// Store the context and parameters, and identify whether the execution is completed (if fired is not empty, it indicates that the execution is completed)
// Here, "complete" indicates that all "existing" functions in the callback function array have been executed;
// But you can call done again to add a callback function. When added, fired is reset to 0.
Fired,
// To avoid firing when already doing so
// If a trigger is being executed, avoid triggering again
Firing,
// Flag to know if the deferred has been canceled
// Identify whether the asynchronous queue has been canceled. After cancellation, the call to done resolve resolveWith is ignored.
Canceled,
// Asynchronous queue definition (this is the positive master, and the local variables above are referenced through the closure)
// The deferred itself
Deferred = {
// Done (f1, f2 ,...)
// Add a successful callback function, which is called immediately when the status is resolved.
Done: function (){
// If the call is canceled, this call is ignored.
If (! Canceled ){
// The benefit of defining the local variables used by the code behind the code block at the beginning of the code block:
// 1. Declare variables to improve code readability;
// 2. Share variables to improve performance
// Note: many years of Java writing experience has developed the habit of starting with global variables and using temporary variables with definitions. JavaScript seems to be somewhat different.
Var args = arguments, // Callback Function Array
I, // traverse the variable
Length, // The length of the Callback Function Array
Elem, // a single callback function
Type, // elem type
_ Fired; // used for temporary backup of fired (fired stores the context and parameters)
// If the execution is completed (that is, the context and parameters are retained in fired)
// Back up the context and parameters to _ fired, and set fired to 0
If (fired ){
_ Fired = fired;
Fired = 0;
}
// Add the functions in arguments to the Callback Function Array
For (I = 0, length = args. length; I <length; I ++ ){
Elem = args [I];
Type = jQuery. type (elem );
// Recursively call an array
If (type = "array "){
// Forcibly specify the context as deferred. In my opinion, you do not need to specify the context here, because the default context is deferred.
Deferred. done. apply (deferred, elem );
} Else if (type = "function "){
Callbacks. push (elem );
}
}
// If you have executed (_ fired indicates that the Deferred status is OK), immediately execute the newly added function.
// Use the previously specified context and parameter args
If (_ fired ){
Deferred. resolveWith (_ fired [0], _ fired [1]);
}
}
Return this;
},
// Resolve with given context and args
// Execute, use the specified context and Parameters
ResolveWith: function (context, args ){
// Execute only when all of the following conditions are met: No cancellation, no execution in progress, no execution completed
// If the call is canceled, completed, or in progress, ignore this call
If (! Canceled &&! Fired &&! Firing ){
// Make sure args are available (#8421)
// Ensure that args is available. A common technique to avoid ReferenceError caused by null and undefined
Args = args | [];
// Change firing to 1 during execution
Firing = 1;
Try {
// Techniques for Traversing Dynamic Arrays
While (callbacks [0]) {
// Note that the specified context is used here, instead of this
Callbacks. shift (). apply (context, args );
}
}
// JavaScript supports try/catch/finally
Finally {
Fired = [context, args];
Firing = 0;
}
}
Return this;
},
// Resolve with this as context and given arguments
// Set the status to Resolved
// The setting is not accurate because isResolved is called to determine the firing and fired statuses.
// It can be understood as execution
Resolve: function (){
Deferred. resolveWith (this, arguments );
Return this;
},
// Has this deferred been resolved?
// Has it been executed (or resolved )?
// If the execution is completed or the execution is completed, it is deemed that the execution has been executed/solved.
// "Already" may be inaccurate, because it is also considered to have been executed during execution.
IsResolved: function (){
// Running
// Or
// The task has been run (that is, fired is not empty/0)
Return !! (Firing | fired );
},
// Cancel
// Cancel the asynchronous queue
// Set the tag bit to clear the function queue
Cancel: function (){
Canceled = 1;
Callbacks = [];
Return this;
}
};
Return deferred;
}

5.4 jQuery. Deferred
Copy codeThe Code is as follows:
// Full fledged deferred (two callbacks list)
// Create a complete asynchronous Queue (including two callback function arrays)
// Asynchronous queue has three statuses: initialization (unresolved), resolved, and rejected ).
// Which callback functions are executed depends on the status.
// After the status changes to resolved or failed, it remains unchanged.
Deferred: function (func ){
// _ Deferred: There is no success or failure state. There are four statuses: initialization, execution in progress, execution completed, and canceled.
// For code reuse, A _ Deferred is first implemented internally.
// FailDeferred references through the closure
Var deferred = jQuery. _ Deferred (),
FailDeferred = jQuery. _ Deferred (),
Promise;
// Add errorDeferred methods, then and promise
JQuery. extend (deferred ,{
// Add the success callback function and failure callback function to their respective queues.
// Convenient method. Two parameters can be array or null.
// Call the success callback function immediately when the status is resolved.
// Call the failed callback function immediately when the status is rejected.
Then: function (doneCallbacks, failCallbacks ){
// Context switches here: Although done returns deferred, fail points to failDeferred. done. If fail is executed, the context changes to failDeferred.
// Simply put:
// Add the callback function doneCallbacks to deferred when calling done.
// Add the callback function failCallbacks to failDeferred when fail is called.
// After this line of expression is executed, the returned result is failDeferred.
Deferred. done (doneCallbacks). fail (failCallbacks );
// Force return deferred
Return this;
},
// Register a callback function. Either resolved or rejected will be called.
// In fact, it is to add the passed functions (arrays) to deferred and failDeferred at the same time.
// It is not stored in a separate Function Array as I imagined.
Always: function (){
// Set the done context to deferred, and the fail context to this
// Is the context of done and fail inconsistent? Consistent! Here this is equal to deferred
// But how should I explain how to set the context here? What is the difference between then and then?
// Fail points to fail and points to failDeferred. done. The default context is failDeferred. The callback function array of failDeferred is referenced by the closure,
// Although the context of the failDeferred. done method is set to deferred, the execution of failDeferred. done is not affected,
// Replace this with deferred at the end of failDeferred. done to implement chained calls,
// That is, the context is not lost during the call. You can continue to call other methods in a chain without causing this confusion.
// Syntactically, always achieve the same effect as then.
// Therefore, this line of code can be rewritten to two rows (similar to the then implementation method), and the effect is equivalent:
// Deferred. done (arguments). fail (arguments );
// Returnr this;
Return deferred. done. apply (deferred, arguments). fail. apply (this, arguments );
},
// Add the failed callback function
// Call immediately when the status is rejected
Fail: failDeferred. done,
// Use the specified context and parameter to execute the failed callback function queue
// Implemented by calling failDeferred. rejectWith ()
RejectWith: failDeferred. resolveWith,
// Call the failed callback function queue
// Implemented by calling failDeferred. resolve ()
Reject: failDeferred. resolve,
// Determine whether the status is successful (resolved)
IsRejected: failDeferred. isResolved,
// Before calling the callback function, call the input success filter function or failure filter function, and use the return value of the filter function as the callback function parameter.
// Finally, a read-only view is returned (implemented by calling promise)
// FnDone is called when the status is resolved
// Call fnFail when the status is rejected
// Other explanations:
// 1. Some articles are translated as "Pipeline mechanism", which cannot be understood literally, so at least it is inaccurate.
// 2. Error understanding: the so-called pipe only places the incoming fnDone and fnFail in the header of the array of the successful and failed queues.
Pipe: function (fnDone, fnFail ){
Return jQuery. Deferred (function (newDefer ){
JQuery. each ({
Done: [fnDone, "resolve"], // done will point to deferred. done later
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 for this deferred
// If obj is provided, the promise aspect is added to the object
// The returned result is an incomplete Deferred interface. Without resolve and reject, the status of the Deferred object cannot be modified,
// This is to prevent external functions from triggering the callback function early. It can be viewed as a read-only view.
//
// For example, $. ajax does not return XMLHttpRequest after 1.5, but returns an object that encapsulates the XMLHttpRequest and Deferred object interfaces.
// The Deferred part is obtained by promise (), so that external functions are not allowed to call resolve and reject, so as to prevent the callback function from being triggered before ajax is completed.
// Retain the call permissions of the two functions to the ajax.
Promise: function (obj ){
If (obj = null ){
// Actually, only one promise is executed. The result of the first execution is stored in the promise variable.
If (promise ){
Return promise;
}
Promise = obj = {};
}
Var I = promiseMethods. length;
// Another loop Traversal method
// I am used:
// 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 will be used
// After the successful queue is executed, the method of canceling the failed queue with columns will be executed.
// After the execution of the failed queue is complete, the method for canceling the successful queue is executed.
// Ensure that only one function queue is executed, that is, either the execution success queue or the execution failure queue;
// That is, the status can only be "yes", "succeeded", or "failed", without cross-call.
// The canceled attributes of deferred and failDeferred can only be referenced through closures, so you do not have to worry about state and context confusion.
Deferred. done (failDeferred. cancel). fail (deferred. cancel );
// Unexpose cancel
// Hide the cancel interface, that is, the function queue cannot be canceled from the external.
Delete deferred. cancel;
// Call given func if any
// Execute the passed func Function
If (func ){
Func. call (deferred, deferred );
}
Return deferred;
}

5.5 jQuery. when
Copy codeThe Code is as follows:
// Deferred helper
// Asynchronous queue tool function
// FirstParam: one or more Deferred objects or JavaScript common objects
When: function (firstParam ){
Var args = arguments,
I = 0,
Length = args. length,
Count = length,
// If arguments. length is equal to 1 and firstParam is Deferred, deferred = firstParam
// Otherwise, create a new Deferred object (if arguments. length is equal to 0 or greater than 1, create a new Deferred object)
// Using jQuery. isFunction (firstParam. promise), you can easily determine whether the object is a Deferred object.
Deferred = length <= 1 & firstParam & jQuery. isFunction (firstParam. promise )?
FirstParam:
JQuery. Deferred ();
// Resolve callback function
Function resolveFunc (I ){
Return function (value ){
// If the input parameter is greater than one, the input parameter is converted to a real array (arguments does not have the slice method, so you can use it)
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
// Callback function queue for successful execution. The context is forced to be the first Deferred object passed in.
Deferred. resolveWith (deferred, sliceDeferred. call (args, 0 ));
}
};
}
// If there is more than one parameter
If (length> 1 ){
For (; I <length; I ++ ){
// Check whether the object is a Deferred object. If yes, call. promise (). then (). Otherwise, ignore
If (args [I] & jQuery. isFunction (args [I]. promise )){
// Add the success callback function and failure callback function to their respective queues.
Args [I]. promise (). then (resolveFunc (I), deferred. reject );
} Else {
// Counter, indicating that it is not a Deferred object, but a common JavaScript Object
-- Count;
}
}
// When the counter is 0, it indicates that the input parameters are not Deferred objects.
// Callback function queue for successful execution. The context is forced to be the first Deferred object passed in.
If (! Count ){
Deferred. resolveWith (deferred, args );
}
// Deferred! = FirstParam, that is, deferred is the newly created Deferred object.
// That is, length = 0
} Else if (deferred! = FirstParam ){
// Callback function queue for successful execution. The context is forced to be a newly created Deferred object.
Deferred. resolveWith (deferred, length? [FirstParam]: []);
}
// Return the read-only view of the first Deferred or newly created Deferred object.
Return deferred. promise ();
}


5.6 Deferred application
L jQuery. ajax ()
N TODO
5.7 Learning Skills
L Closure
Copy codeThe Code is as follows:
Function (){
Var guid = 1;
Return function (){
Return guid ++;
}
}
Var defer = ();
Console.info (defer (); // 1
Console.info (defer (); // 2
Console.info (defer (); // 3
Console.info (defer (); // 4

L common tips for avoiding ReferenceError caused by null and undefined
Args = args | [];
L skills for Traversing Dynamic Arrays
While (callbacks [0]) {
Callbacks. shift (). apply (context, args );
}
L try/catch/finally implement error handling
Syntax
Description
Try {
// TryStatements
} Catch (exception ){
// CatchStatements
} Finally {
// FinallyStatements
}
TryStatements
Required.
An error may occur.
Exception
Required. Any variable name.
The initialization value of exception is the thrown error value.
CatchStatements
Optional.
The statement that handles errors in the associated tryStatement.
FinallyStatements
Optional.
The statements that are unconditionally executed after all other processes occur.
L chained object: Implement chained call by returning this
Method
Return Value
Done
This (deferred)
ResolveWith
This (deferred)
Resolve
This (deferred)
Cancel
This (deferred)
L code reuse $. each
JQuery. each ({
Done: [fnDone, "resolve"], // done will point to deferred. done later
Fail: [fnFail, "reject"]
}, Function (handler, data ){
// Reuse public code
});
5.8 follow-up
L Deferred application in jQuery
L Deferred Custom Application

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.