-
Notifications
You must be signed in to change notification settings - Fork 25
Open
Description
利用 jQuery.when 简化代码
最近有一些项目,是从已有的功能上新增一些数据,比如个人账户中新增一些数据。后端并没有在原有接口上提供所需数据,而是希望我们调用另一个接口,这个接口仅仅提供新增的数据。
由于新接口和旧接口在数据上并没有依赖关系,所以我们可以等两个接口都请求完成后将数据填充到 DOM 结构中。在这个问题的解决过程中就出现了一些不太简洁的代码,比如:
var len = 2, data = {}
cb = function () {...}
//一个请求
$.ajax({
url: url1,
...
}).then(function (d) {
len--
$.extend(data, d)
if (len === 0) {
cb(data)
}
})
//又一个请求
$.ajax({
url: url2,
...
}).then(function (d) {
len--
$.extend(data, d)
if (len === 0) {
cb(data)
}
})这种解决方案虽然能处理当前项目中的实际问题,但是当这类无序的异步请求是 N 个的时候,这种方法就有点捉襟见肘了。而利用 jQuery.when 方法,即能很好的解决这些问题,而且能够使代码简洁优雅易于维护。
$.when($.ajax({
url: url1,
...
}), $.ajax({
url: url2,
...
})).done(function (data1, data2) {...}).fail(function () {...})简洁明了了许多吧:smile:
## jQuery.when 的参数
上面提到将多个异步请求作为参数传入 jQuery.when 方法中,这个描述并不正确,因为 jQuery.when 接受的是延迟对象(jQuery.Deferred),巧在 jQuery.ajax 方法返回的 jqXHR 对象(浏览器原生 XHR 对象的超集)就是一个延迟对象(jQuery 1.5+),所以看上去我们是将 jqXHR 对象作为了参数,这确实让人产生了一定的误解。
在处理普通的延迟问题的时候,我们就需要在异步方法中明确地返回延迟对象。
var dfd1 = new $.Deferred(),
dfd2 = new $.Deferred()
function wait1 (dfd) {
setTimeout(function () {
dfd.resolve('wait1 done')
}, 1000)
return dfd.promise()
}
function wait2 (dfd) {
setTimeout(function () {
dfd.resolve('wait2 done')
}, 2000)
return dfd.promise()
}
$.when(wait1(dfd1), wait2(dfd2)).done(function (data1, data2) {
console.log(data1) // 'wait1 done'
console.log(data2) // 'wait2 done'
})## done、fail、then 方法
jQuery.when 方法返回的是一个 Promise 对象(延迟对象的一个子集),可以调用它的 done、fail、then 方法执行回调函数。这里列一下这些方法中回调函数的执行条件。
- done 所有延迟对象都执行成功(resolved)时执行;
- fail 有一个延迟对象失败(rejected)时即执行,即使还有未完成的延迟对象;
- then 所有延迟对象完成后执行,可以传入两个回调函数作为参数,第一个参数在全部延迟对象成功时执行,第二个参数在有一个或多个延迟对象失败时执行。
另外需要注意的是,当 jQUery.when 方法被传入了一个以上的参数时,回调函数中的参数可能是一个数组。因为在传递给一个延迟对象的解决(resolved)事件为多个值的情况下,相应的参数将是这些值组成的数组。
var dfd1 = new $.Deferred(),
dfd2 = new $.Deferred()
function wait1 (dfd) {
setTimeout(function () {
dfd.resolve('wait1', 'done')
}, 1000)
return dfd.promise()
}
function wait2 (dfd) {
setTimeout(function () {
dfd.resolve('wait2', 'done')
}, 2000)
return dfd.promise()
}
$.when(wait1(dfd1), wait2(dfd2)).done(function (data1, data2) {
console.log(data1) // ['wait1', 'done']
console.log(data2) // ['wait2', 'done']
})## 参考资料
jQuery.ajax API 传送门
jQuery.when API 传送门
## Thanks