jquery Source Analysis-05 Asynchronous Queue Deferred Use introduction _jquery

Source: Internet
Author: User
Tags closure
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

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.