您的位置:首页 > Web前端 > JQuery

jquery中的工具方法--Deferred和when

2016-06-06 14:41 507 查看
在jquery1.5版本以后,Deferred和promise就是jquery中非常常用的两个功能,并且在这个版本利用Deferred又完全重写了ajax模块。Deferred对象是有jquery.Deferred构造的,$.Deferred在jquery代码中,分别在promise方法、Dom ready、ajax模块、动画模块被使用

Deferred的用法

var defer = $.Deferred();
function aaa(){
console.log("aaa");
defer.resolve();//完成态 相当于callbacks中的fire
}
aaa();
//相当于callbacks中的add方法 通过done改变状态
defer.done(function(){
console.log('success');
});

var defer = $.Deferred();
function runAsync(){
setTimeout(function(){
console.log('执行完成');
defer.resolve('data');
},2000)
return defer.promise();
}
defer.done(function(data){
console.log(data);
})
defer.fail(function(data){
console.log(data);
})
var d = runAsync();
d.done(function(data){
console.log(data);
})
d.then(function(data){
console.log(data);
})


这里需要说明一下deferred和promise的区别,deferred相当于promise的继承类,相比于promise方法,deferred可以通过resolve、reject和 notify改变回调的状态,而promise不能修改回调的状态

$.Deferred的实现

异步队列的方法

添加回调函数方法

deferred.done(doneCallbacks[,doneCallbacks]):添加成功回调函数,当异步队列处于成功状态时被调用

deferred.fail(failCallbcks[,failCallbacks]): 添加失败回调函数,当异步队列处于失败状态时被触发

deferred.progress(progressCallbacks):添加消息回调函数

deferred.then(doneCallbacks,failCallbacks[,progressCallbacks]): 添加成功回调函数、失败回调函数、消息回调函数

deferred.always(alwaysCallbacks[,alwaysCallbacks]):添加回调函数,当异步队列处于成功或失败状态时调用

执行回调函数方法

deferred.resolve(args): 使用指定的参数调用所有的成功回调函数

deferred.resolveWith(context[,args]): 使用指定的上下文和参数调用所有的成功回调函数,异步队列进入成功状态

deferred.reject(args): 使用指定的参数调用所有失败回调函数,异步队列进入失败状态

deferred.rejectWith(context[.args]: 使用指定的上下文和参数调用所有失败回调函数,异步对垒进入失败状态

deferred.notify(args): 使用指定的参数调用所有的消息回调函数

deferred.notifyWith(context[,args]):使用指定的上下文和参数调用所有的消息回调函数

判断当前状态

deferred.state():判断异步队列的当前状态

工具

deferred.pipe(
[doneFilter]
[,failFilter]
[,progressFilter]
): 返回一个新的异步队列的只读副本,通过过滤函数过滤当期那异步队列的状态和值

deferred.promise([target]):返回当前Deferred对象的制度副本,或者为普通对象增加异步队列的功能

实现过程

方法jQuery.Deferred(func)创建异步队列的5个关键步骤如下

创建三个$.Callbacks对象,分别表示函数执行的三个状态,即未完成、完成和失败,并设置初始状态为待定(pending)

创建异步队列的只读副本promise,其中包含了方法done() 、fail()、progress()、state()、isRejected()、then()、always()、pipe()、promise()

定义异步队列deferred

a. 把只读副本promise中的方法添加到异步队列deferred中

b. 为异步队列deferred添加触发执行成功、失败、消息回调函数的方法,包括resolve()、resolveWith()、reject()、rejectWith()、notify()、notifyWith()

c. 为异步队列deferred添加设置状态的回调函数

如果传入函数参数func,则调用。

返回异步队列deferred

// 扩展了工具方法Deferred和when
// $.Deferred();
// $.when()
// 延迟对象是基于callbacks对象实现的
// 实现了对异步的的统一管理

// 提供了always then promise pipe when 等实用的方法
jQuery.extend({

Deferred: function( func ) {
var tuples = [
// action, add listener, listener list, final state
// 分别对应完成态 失败态和未完成态
// resolve相当于callbacks对象中的fire方法 done相当于add方法  resolved为状态
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory") ]
],
state = "pending",
promise = {
// 该方法返回当前的状态
state: function() {
return state;
},
//完成态和失败态都执行该操作
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
},
//then方法同时绑定完成态、失败态和未完成态三个回调函数
then: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
return jQuery.Deferred(function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
// deferred[ done | fail | progress ] for forwarding actions to newDefer
// 对各个状态添加回调函数
deferred[ tuple[1] ](function() {
var returned = fn && fn.apply( this, arguments );
//确定回调函数的返回值
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
} else {
newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
}
});
});
fns = null;
}).promise();
},
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
return obj != null ? jQuery.extend( obj, promise ) : promise;
}
},
deferred = {};

// Keep pipe for back-compat
promise.pipe = promise.then;

// Add list-specific methods
// 对映射数组进行遍历操作
jQuery.each( tuples, function( i, tuple ) {
var list = tuple[ 2 ],//callback回调
stateString = tuple[ 3 ];//状态字符串

// promise[ done | fail | progress ] = list.add
// 对done、fail和progress等同于list.add方法 并将添加回调的方法添加至promise对象中
promise[ tuple[1] ] = list.add;

// Handle state
// 只有完成态和失败态有statestring
if ( stateString ) {
list.add(function() {
// state = [ resolved | rejected ]
state = stateString;

//当完成态的回调被调用时 失败态和进行态就不能被调用
//i^1为位运算符 当i为1时 结果为0,当i为0时 结果为1
// [ reject_list | resolve_list ].disable; progress_list.lock
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
}

// deferred[ resolve | reject | notify ]
deferred[ tuple[0] ] = function() {
deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
return this;
};
deferred[ tuple[0] + "With" ] = list.fireWith;
});

// Make the deferred a promise
// 将promise和deferred合并
promise.promise( deferred );

// Call given func if any
if ( func ) {
func.call( deferred, deferred );
}

// All done!
return deferred;
},


$.when()的用法

$.when方法实现多个回调函数的控制

function aaa(){
var defer = $.Deferred();
defer.resolve();
return defer;
}

function bbb(){
var defer = $.Deferred();
defer.resolve();

return defer;
}
//需求:当两个回调都成功的时候执行操作
//when主要是针对多延迟对象的操作
$.when(aaa(),bbb()).done(function(){
alert('成功');
}).fail(function(){
alert('失败');
})


$.when方法中,只有参数中的所有函数都为resolve时,才执行done操作,只要有一个为reject,立即执行fail操作

$.when的实现

接收若干个对象,参数仅一个且返回值不是Deferred对象将立即执行回调函数

返回值为Deferred对象和非Deferred对象混杂时,对于非Deferred对象的计数器减一

当所传参数中所有的Deferred对象都resolve后,执行回调

// Deferred helper

when: function( subordinate /* , …, subordinateN */ ) {

var i = 0,

resolveValues = slice.call( arguments ),//将arguments变为数组

length = resolveValues.length,

// the count of uncompleted subordinates
// 记录未完成态的回调函数的个数
// 当传入的参数为0或传入的参数的返回值不是延迟对象的时候 length为0;
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,

// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
// 若只有一个参数,延迟对象即为传入的参数
// 若没有参数或参数大于1 创建新的延迟对象
deferred = remaining === 1 ? subordinate : jQuery.Deferred(),

// Update function for both resolve and progress values
// 更新计数器
updateFunc = function( i, contexts, values ) {
return function( value ) {
contexts[ i ] = this;
values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
if ( values === progressValues ) {
deferred.notifyWith( contexts, values );
//当计数器减为0时 执行resolve
} else if ( !(--remaining) ) {
deferred.resolveWith( contexts, values );
}
};
},

progressValues, progressContexts, resolveContexts;

// add listeners to Deferred subordinates; treat others as resolved
if ( length > 1 ) {
progressValues = new Array( length );
progressContexts = new Array( length );
resolveContexts = new Array( length );
for ( ; i < length; i++ ) {
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
resolveValues[ i ].promise()
.done( updateFunc( i, resolveContexts, resolveValues ) )
.fail( deferred.reject )//只要有一个失败 触发reject
.progress( updateFunc( i, progressContexts, progressValues ) );
} else {
//当参数的返回值不是延迟对象 对remaining减1
--remaining;
}
}
}

// if we're not waiting on anything, resolve the master
// 针对没有参数或都是完成态的情况
if ( !remaining ) {
deferred.resolveWith( resolveContexts, resolveValues );
}

return deferred.promise();
}
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jquery 延迟对象