deferred object is jQuery's callback function solution, which solves the problem of how to deal with time-consuming operations, such as some Ajax operations, animation operations, etc. (P.s: Keep up with the previous section: https://www.cnblogs.com/greatdesert/p/11433365.html)
Asynchronous queues have three states: pending, resolved, and rejected, and are initially pending
We can use jQuery.Deferred to create an asynchronous queue and return an object that contains the following actions:
Do (fn/arr); Add a successful callback function, which is called when the asynchronous queue is in a successful state, with the same parameters: jQuery.Callbacks(flags).add(fn/arr)
fail(fn/arr) Add a failed callback function with the same parameters as above
progress(fn/arr); Add a message callback function with the same parameters
then(donefn/arr,failfn/arr,profn/arr); at the same time, successful callback function, failure callback function and message callback function are added.
always(fn/arr); add callback function to doneList and failList, that is, save two references, when the asynchronous queue is in a successful or failed state; parameters can be functions, function lists
state() Returns the current status of the asynchronous queue, pending, resolved, or rejected
promise(obj) * If the obj parameter object is set, the method of adding an asynchronous queue to the obj object is returned. If the parameter obj is not set, a read-only copy of the current Deferred object is returned
If $. Diferred() is called to create an asynchronous queue, the returned object can call the following methods:
Writby: Great Desert QQ:22969969
resolve(args); call all successful callback functions with specified parameters, and the asynchronous queue enters a successful state, and then cannot be called again
reject(args); invoke all failed callback functions with specified parameters, and the asynchronous queue enters a failed state
notify(args) callback functions using specified parameters
resolveWith(context,args); invoke all successful callback functions with specified context and parameters, and the asynchronous queue enters a successful state
rejectWith(context,args); invoke all failed callback functions with the specified context and parameters, and the asynchronous queue enters a failed state
NotfyWith (context, args); Call all message callback functions with the specified context and parameters
Is it similar to fire and FireWithin of Callback introduced in the previous section? Defferred is implemented internally through the Callback() callback function list, for example:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="http://libs.baidu.com/jquery/1.7.1/jquery.js"></script> </head> <body> <script> function f1(x){console.log('f1 '+x);} function f2(x){console.log('f2 '+x);} function f3(x){console.log('f3 '+x);} var t = $.Deferred(); //Create an asynchronous queue t.done(f1).fail(f2).progress(f3); //Add successful callback functions, failed callback functions and message list callback functions. Equate to t.then(f1,f2,f3); t.notify('test'); //Trigger a list of all message functions, output:f3 test t.resolve('done'); //Triggering all successful callback functions,output:done t.reject('fail'); //Without output, the list of failed callback functions is disabled when a successful callback function is triggered, and vice versa. t.progress(f1); //output:f1 test. This is because the message callback function has been called before, and the context and parameters are saved. If it has not been called before, there will be no output. </script> </body> </html>
The output is as follows:
Source code analysis
The implementation principle of asynchronous queue is to define three callback function lists through jQuery.Callbacks, store success, failure and message callback functions respectively, and then return an object. On this object, do, fail and progress are set to correspond to the adds of the three callback function lists, so that callback functions with different states are added separately.
Deferred is mounted directly into jQuery through the jQuery.extend function. The structure is as follows:
jQuery.extend({ Deferred: function( func ) { var doneList = jQuery.Callbacks( "once memory" ), //List of successful callback functions failList = jQuery.Callbacks( "once memory" ), //List of failed callback functions progressList = jQuery.Callbacks( "memory" ), //List of message callback functions ;The list of these three callback functions stores the trigger functions we added. state = "pending", //Initial state:pending lists = { //The latter method traverses variables list To add a method to an asynchronous queue deffred.resolve(),resolveWith(),reject(),rejectWith(),notify()and notifyWith() resolve: doneList, reject: failList, notify: progressList }, promise = { //Read-only copy of asynchronous queue /*slightly*/ }, deferred = promise.promise({}), //Asynchronous queue key; for ( key in lists ) { //Add methods to trigger success, failure, message callback functions, after execution deferred More objects resolve(),resolveWith(),reject(),rejectWith(),notify()and notifyWith()Method. deferred[ key ] = lists[ key ].fire; deferred[ key + "With" ] = lists[ key ].fireWith; } // Handle state deferred.done( function() { //Add three successful callback functions to set the status to success(resolved),Disable Failure List Function List and Lock Message Callback Function List state = "resolved"; }, failList.disable, progressList.lock ).fail( function() { //Add three failed callbacks to Korean Sugar to set the status to fail(rejected),Disable Success List Function List and Lock Message Callback Function List state = "rejected"; }, doneList.disable, progressList.lock ); // Call given func if any if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; //Return to an asynchronous queue deffrred }, //... })
As you can see, $. Deferred finally returns deferred, the layout variable, and deferred is the return value of promise.promise({}). Let's look at the implementation of promise:
promise = { //Read-only copy of asynchronous queue done: doneList.add, //Add a successful callback function, referring to the corresponding list of callback functions callbacks.add(fn/arr)Method, the same below fail: failList.add, //Add a failed callback function progress: progressList.add, //Add message callback function state: function() { //Returns the current status of the asynchronous queue:pending,resolved,rejected One of return state; }, // Deprecated isResolved: doneList.fired, isRejected: failList.fired, then: function( doneCallbacks, failCallbacks, progressCallbacks ) { //Adding success callback function, failure callback function and message callback function at the same time deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); return this; }, always: function() { //Add callback functions to doneList and failList In this way, two references are saved and called when the asynchronous queue is in a successful or failed state deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); return this; }, pipe: function( fnDone, fnFail, fnProgress ) { //Filter the status and parameters of the current asynchronous queue and return a copy of a new asynchronous queue,Usually not needed return jQuery.Deferred(function( newDefer ) { jQuery.each( { done: [ fnDone, "resolve" ], fail: [ fnFail, "reject" ], progress: [ fnProgress, "notify" ] }, 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, newDefer.notify ); } else { newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ 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 promise: function( obj ) { //If set obj The parameter object is obj Object adds an asynchronous queue method and returns it. If no parameters are set obj,Return to the current Deferred A read-only copy of the object, if ( obj == null ) { //If obj Empty obj = promise; //Then return promise object(It's the upper level of scope chain. promise object) } else { for ( var key in promise ) { //Otherwise, traversal promise obj[ key ] = promise[ key ]; //take promise All methods and attributes are saved to obj in } } return obj; //Last return obj } },
Deferred simply manages the list of Callbacks callback functions, resulting in a new $. Defferred interface, which adds a state to represent the status of an asynchronous queue.