异步队列Deferred Object
一)jQuery.Callbacks( flags )
1.总体结构
该函数返回一个链式工具对象(回调函数列表),用于管理一组回调函数。
2.源码分析
1.工具函数createFlags(flags)
该函数用于将字符串标记转换为对象格式标记,并把转换结果缓存起来。
// String to Object flags format cache var flagsCache = {}; // Convert String-formatted flags into Object-formatted ones and store in cache function createFlags( flags ) { var object = flagsCache[ flags ] = {}, i, length; flags = flags.split( /\s+/ ); for ( i = 0, length = flags.length; i < length; i++ ) { object[ flags[i] ] = true; } return object; }
2.工具函数add( args )
jQuery.Callbacks = function( flags ) { // Convert flags from String-formatted to Object-formatted // (we check in cache first) flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; var // Actual callback list list = [], // Add one or several callbacks to the list add = function( args ) { var i, length, elem, type, actual; for ( i = 0, length = args.length; i < length; i++ ) { elem = args[ i ]; type = jQuery.type( elem ); if ( type === "array" ) { // Inspect recursively add( elem ); } else if ( type === "function" ) { // Add if not in unique mode and callback is not in if ( !flags.unique || !self.has( elem ) ) { list.push( elem ); } } } },
3.工具函数fire( context, args )
使用指定的上下文context和参数args调用数组list中的回调函数
jQuery.Callbacks = function( flags ) { var // Actual callback list list = [], // Stack of fire calls for repeatable lists stack = [], // Last fire value (for non-forgettable lists) //memory为undefined表示当前回调函数列表没有被触发过 memory, // Flag to know if list was already fired fired, // Flag to know if list is currently firing firing, // First callback to fire (used internally by add and fireWith) firingStart, // End of the loop when firing firingLength, // Index of currently firing callback (modified by remove if needed) firingIndex, // Fire callbacks fire = function( context, args ) { args = args || []; //如果当前不是memory模式则设置memory为true, // 间接地表示当前回调函数列表已经被触发过 //如果是memory模式,则memory被赋值为[context, args],表示当前回调函数列表被触发过 memory = !flags.memory || [ context, args ]; fired = true; //变量firing表示回调函数列表是否正在执行 firing = true; firingIndex = firingStart || 0; firingStart = 0; firingLength = list.length; for ( ; list && firingIndex < firingLength; firingIndex++ ) { if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { memory = true; // Mark as halted break; } } firing = false; if ( list ) { if ( !flags.once ) { if ( stack && stack.length ) { memory = stack.shift(); self.fireWith( memory[ 0 ], memory[ 1 ] ); } } else if ( memory === true ) { self.disable(); } else { list = []; } } }, // Actual Callbacks object self = { // Have the list do nothing anymore disable: function() { list = stack = memory = undefined; return this; }, // Is it disabled? disabled: function() { return !list; },
4.callbacks.add()
添加回调函数到列表中,通过工具函数add(args)实现。
在memory模式下,并且回调函数列表未在执行中,并且已经被触发过,则立即执行回调函数。
// Add a callback or a collection of callbacks to the list add: function() { if ( list ) { var length = list.length; add( arguments ); // Do we need to add the callbacks to the // current firing batch? if ( firing ) { firingLength = list.length; // With memory, if we‘re not firing then // we should call right away, unless previous // firing was halted (stopOnFalse) } else if ( memory && memory !== true ) { firingStart = length; fire( memory[ 0 ], memory[ 1 ] ); } } return this; },
5.callbacks.remove()
从回调函数列表中移除一个或者一组回调函数,移除前修正firingLength和firingIndex
remove: function() { if ( list ) { var args = arguments, argIndex = 0, argLength = args.length; for ( ; argIndex < argLength ; argIndex++ ) { for ( var i = 0; i < list.length; i++ ) { if ( args[ argIndex ] === list[ i ] ) { // Handle firingIndex and firingLength if ( firing ) { if ( i <= firingLength ) { firingLength--; if ( i <= firingIndex ) { firingIndex--; } } } // Remove the element list.splice( i--, 1 ); // If we have some unicity property then // we only need to do this once if ( flags.unique ) { break; } } } } } return this; },
6. callbacks.disable() 和 callbacks.disabled()
1)callbacks.disable():禁用回调函数列表
2)callbacks.disabled():判断函数列表是否被禁用
// Have the list do nothing anymore disable: function() { list = stack = memory = undefined; return this; }, // Is it disabled? disabled: function() { return !list; },
禁用后无法添加、移除、触发回调函数,并会立即停止正在执行的回调函数。
7.锁定 callbacks.lock()、 callbacks.locked()
// Lock the list in its current state lock: function() { //这会导致无法再次触发回调函数 stack = undefined; if ( !memory || memory === true ) { self.disable(); } return this; }, // Is it locked? locked: function() { return !stack; },
二)jQuery.Deferred(func)
该方法返回一个链式工具对象,我们把该链式工具对象称为"异步队列"。
异步队列的三种状态:
1)待定(pending):初始时处于的状态
2)成功(resolved):调用方法deferred.resolved(args)或resolvedWith(context, args)
将改变异步队列为成功状态,并且立即执行添加的所有"成功回调函数"。
3)失败(rejected):调用方法deferred.reject(args)和方法deferred.rejectWith(context, args)
则改变状态为失败状态,并立即执行所有"失败回调函数"。
一旦异步队列进入成功或者失败状态,就会保持它的状态不变。再次调用以上方法就会被忽略。
异步队列内部维护了三个函数列表:成功回调函数列表、失败回调函数列表、消息回调函数列表。
//可选参数func Deferred: function( func ) { var doneList = jQuery.Callbacks( "once memory" ), failList = jQuery.Callbacks( "once memory" ), progressList = jQuery.Callbacks( "memory" ), //设置初始状态 state = "pending", lists = { resolve: doneList, reject: failList, notify: progressList }, //创建异步队列的只读副本 promise = { done: doneList.add, fail: failList.add, progress: progressList.add, state: function() { return state; }, // Deprecated isResolved: doneList.fired, isRejected: failList.fired, //同时添加成功、失败和消息回调函数 then: function( doneCallbacks, failCallbacks, progressCallbacks ) { deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); return this; }, //用于将回调函数同时添加到成功回调函数列表和失败回调函数列表 always: function() { deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); return this; }, pipe: function( fnDone, fnFail, fnProgress ) { 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 ( obj == null ) { obj = promise; } else { for ( var key in promise ) { obj[ key ] = promise[ key ]; } } return obj; } }, deferred = promise.promise({}), key; for ( key in lists ) { deferred[ key ] = lists[ key ].fire; deferred[ key + "With" ] = lists[ key ].fireWith; } // Handle state deferred.done( function() { state = "resolved"; }, failList.disable, progressList.lock ).fail( function() { state = "rejected"; }, doneList.disable, progressList.lock ); // Call given func if any if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; },
三)jQuery.when(deferreds)
该方法提供了基于一个或者多个对象的状态来执行回调函数的功能,
通常是基于具有异步事件的异步队列。
原文地址:https://www.cnblogs.com/Shadowplay/p/9831097.html