本文详解jQuery 1.5+版本引入的Deferred延迟对象。涵盖Ajax链式回调、done/fail/then方法区别,$.when处理多异步逻辑,以及通过$.Deferred()手动创建和状态管理(resolve/reject/promise)的高级用法,帮助提升异步代码可读性。
jQuery Deferred对象与Ajax链式回调基础
自jQuery 1.5版本起,库中引入了deferred对象(延迟对象),专门用于处理在未来某一时刻触发的回调函数。与此同时,jQuery重写了Ajax方法,使其直接返回一个deferred对象实例。接下来我们将深入探讨deferred对象的具体用法。首先是Ajax的链式回调机制。
// ajax方法返回的是一个deferred对象,可以直接使用链式写法
$.ajax('test.json').done(function(resp){
// done 相当于success回调,其中默认的参数为success回调的参数
alert('success');
}).fail(function(){
// fail 相当于error回调
alert('error');
});
开发者可以连续编写多个回调函数,这些函数将严格按照定义的顺序依次执行。
$.ajax('test.json').done(function(resp){
// done 相当于success回调,其中默认的参数为success回调的参数
alert('success');
}).done(function(){
// do something...
}).done(function(){
// do something...
});
deferred对象还提供了then方法,该方法整合了done和fail的功能。它接受一个或两个参数:若传入两个参数,第一个作为done的回调,第二个作为fail的回调;若仅传入一个参数,则默认视为done的回调函数。
var success = function(){
alert('success');
};
var error = function(){
alert('error');
};
// 两个参数
$.ajax('test.json').then(success, error);
// 一个参数
$.ajax('test.json').then(success);
$.when方法处理多异步逻辑
jQuery还提供了$.when(deferreds)方法,用于执行一个或多个延迟对象的回调。当传入的参数为延迟对象时,该方法会等待所有异步操作完成后,再执行相应的回调函数。
$.when($.ajax('test.json'), $.ajax('demo.json')) .done(function(){
alert('success');
}).fail(function(){
alert('error');
});
逻辑上,只有当所有异步操作均成功时,才会执行done中的回调;若任一失败,则执行fail中的回调。值得注意的是,done回调函数的默认参数数量与$.when方法接收的参数数量一致。如果传入$.when的是普通对象而非deferred对象,done回调将立即执行,且默认参数为传入的普通对象本身。
// 当传入when方法的参数只是普通对象时
$.when({test: 'test'}).done(function(resp){
console.log(resp.test); // 'test'
}).fail(function(){
// 由于传入的对象不是deferred对象,那么就不会调用fail中的回调了
})
Ajax二次封装提升代码可读性
当需要等待两个或多个异步操作结束才调用回调,且这些Ajax请求可能需要修改传输方式(type)或传递数据(data)时,代码会变得杂乱且可读性差。因此,对Ajax进行二次封装以提高代码可读性显得尤为重要。
var ajax = function(url, type, param){
return $.ajax({
url: url,
type: type,
data: param || {}
});
};
ajax('test.json').done(function(resp){
alert('success');
}).fail(function(){
alert('error');
});
手动创建Deferred与状态管理
此外,还有一个always()方法常被忽略,它接受一个回调函数。与done和fail不同,无论异步操作成功还是失败,always中的回调都会执行。deferred对象不仅限于jQuery的Ajax方法,它提供了一系列接口,大大提升了其通用性。例如,面对一个耗时较长的方法:
function a(){
function b(){
alert('start');
}
setTimeout(b, 3000);
}
若要在该方法执行后调用回调,不能直接使用$.when(),因为当$.when()的参数不是deferred对象时,会直接调用done或always中的回调。此时需使用deferred对象的其他方法,对上述代码进行改写:
function a(){
var def = $.Deferred(); // 创建deferred对象
function b(){
alert('start');
def.resolve(); // 改变deferred对象的状态
}
setTimeout(b, 3000);
return def;
}
$.when(a()).done(function(){
alert("It's callback");
});
分析如下:1)$.Deferred()方法用于创建一个deferred对象;2)def.resolve()用于改变deferred对象的状态。deferred对象具有三种状态:未完成、成功和失败。它包含resolve()和reject()两个方法,分别用于将状态更改为成功或失败。上述写法存在缺陷,因为返回的deferred对象允许外部改变状态。为此,jQuery提供了promise()方法,它在deferred对象基础上返回一个新的实例,该实例仅暴露状态观察能力,而不具备改变状态的方法,类似于只读的deferred对象。因此,示例可改写为:
function a(){
var def = $.Deferred(); // 创建deferred对象
function b(){
alert('start');
def.resolve(); // 改变deferred对象的状态
}
setTimeout(b, 3000);
return def.promise();
}
$.when(a().reject()).done(function(){ // reject()方法无效
alert("It's callback");
});
以上内容为本文的全部讲解,希望对各位的学习有所帮助,也欢迎大家继续支持本站。