JS是单线程语言,把每一件事情(包括GUI事件和渲染)都放在一个线程里来处理是一个很好的程序模型,因为这样就无需再考虑线程同步这些复杂问题。
但js暴露了应用开发中的一个严重问题,单线程环境看起来对用户请求响应迅速,但是当线程忙于处理其它事情时,就不能对用户的鼠标点击和键盘操作做出响应。
jQuery.deferred异步模型提供了一个抽象的非阻塞的解决方案。
jQuery.deferred()在jQ中常用的有:
- promise
- Ajax模块
- 动画模块
- DOM ready
jQuery.Deferred(func)在jQuery.Callbacks(flags)的基础上,为回调函数增加了状态,提供了多个回调函数列表。可以通过调用方法deferred.done/fail/progress/then/always()添加成功调回调函数、失败回调函数、消息回调函数到对应的成功、失败、消息回调函数列表中,并且可通过调用方法derred.resolve/resolveWith/rejectWith/notify/notifyWith()分别触发成功、失败、消息回调函数列表。
异步队列有三种状态:pending,resolved,rejected分别是待定、成功、失败。
异步队列的方法列表如下:
jQuery.Deferred(func)创建异步队列步骤:
- 创建成功、失败、消息回调函数列表,设置初始状态为pending(待定);
- 创建异步队列的只读副本promise,其中包含了方法done()、fail()、progress()、state()、isResolved()、isRejected()、then()、always()、pipe()、promise()
- 定义异步队列deferred
- 如果传入函数参数func,则调用
- 返回异步队列deferred
jQuery.extend({
Deferred: function( func ) {
//成功回调函数列表,once表示回调函数列表只能被触发一次,memory表示会记录上一次触发回调函数列表时的参数,触发后添加的任何回调函数都将用记录的参数值立即调用
var doneList = jQuery.Callbacks( "once memory" ),
//失败回调函数列表
failList = jQuery.Callbacks( "once memory" ),
//消息回调函数
progressList = jQuery.Callbacks( "memory" ),
//初始状态,在调用方法deferred.resolve()或deferred。resolveWith()后被设置为字符串“resolved”,表示成功状态,调用方法deferred.reject()或deferred.resolveWith()后被设置为字符串“rejected”,表示失败状态
state = "pending",
lists = {
resolve: doneList,
reject: failList,
notify: progressList
},
//异步队列的只读副本,前三个是引用对应的回调函数列表的方法callbacks.add()
promise = {
done: doneList.add,
fail: failList.add,
progress: progressList.add,
//返回状态
state: function() {
return state;
},
// Deprecated
isResolved: doneList.fired,
isRejected: failList.fired,
//用户将回调函数同事添加到成功回调函数列表doneList和失败回调函数列表failList,保存两份引用,当异步队列处于成功或失败状态时被调用
then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
//采用链式语法依次调用方法done(),fail(),progress()逐个添加回调函数,并返回this以绩效支持链式语法
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
// 用于返回当前异步队列的只读副本,或为一个javascript对象增加只读副本中的方法并返回。
promise: function( obj ) {
//如果没有传入参数,则返回当前异步队列的只读副本promise
if ( obj == null ) {
obj = promise;
} else {
//若传入了参数obj,则把只读副本promise中的方法添加到参数obj中,从而似的参数obj具有异步队列行为,但是只包含了添加回调函数和判断状态的方法
for ( var key in promise ) {
obj[ key ] = promise[ key ];
}
}
return obj;
}
},
//异步队列把只读副本promise中的方法添加到异步队列deferred中
deferred = promise.promise({}),
key;
//为异步队列添加触发成功、失败、消息回调函数列表的方法
for ( key in lists ) {
deferred[ key ] = lists[ key ].fire;
deferred[ key + "With" ] = lists[ key ].fireWith;
}
// 添加设置状态的回调函数
deferred.done( function() {
state = "resolved";
}, failList.disable, progressList.lock ).fail( function() {
state = "rejected";
}, doneList.disable, progressList.lock );
// 若传入函数参数func,则执行
if ( func ) {
func.call( deferred, deferred );
}
// 返回异步队列deferred
return deferred;
},
});
时间: 2024-10-05 09:15:59