根据 $.when 的 jQuery 文档,如果任何一个参数承诺失败,那么 .when 不会等待,并且会立即失败。它也不会取消其他承诺。
有没有办法强制 $.when 真正等到它的所有承诺都完成?或者,我可以/应该使用其他方法吗?
也许这是使用错误工具的情况,但我试图在同时获取两个部分的数据时阻止 UI(加载微调器)。我可以独立处理任一/两个部分的故障。当(且仅当)所有承诺都完成(成功或失败)时,我想解锁该页面。
在下面的示例代码中,“callSvc”是一个测试方法,它采用字符串“service”标识符、以毫秒为单位的服务器睡眠时间以及网络调用是否失败的指示符。
callSvc("sync", 0, false)
.then(function (result) {
return $.when(
callSvc("ebill", 4000, false)
.then(function (a, b, c, d) {
debugger;
}),
callSvc("epol", 2000, true)
.done(function () {
// set up epol section with data
debugger;
})
.fail(function () {
// set up epol section for failure
debugger;
})
).done(function (ebill, epol) {
// just here to test ways to stop early-fail
debugger;
}).fail(function () {
// just here to test ways to stop early-fail
debugger;
})
}).fail(function (err) {
// show message
debugger;
}).always(function () {
// unblock the screen
debugger;
});
对于多参数
$.when()
或 Promise.all
,一旦任何调用失败,规范就会失败。 Promise.allSettled
,在回答此问题后于 2019-2020 年引入,具有非常相似的行为,您可以使用它。
使用一个小的包装方法,您可以以与
Promise.allSettled
类似的方式将失败转变为(暂时)成功。这相当于调用 catch
,但使用两个参数 then
调用:
function wrapWithSuccessFlag(promise) {
return promise.then(
successfulValue => { return { status: 'fulfilled', value: successfulValue }; },
failureReason => { return { status: 'rejected', reason: failureReason }; });
}
callSvc("sync", 0, false).then(result => {
return $.when(
wrapWithSuccessFlag(callSvc("ebill", 4000, false)
.then(function (a, b, c, d) {
debugger;
})),
wrapWithSuccessFlag(callSvc("epol", 2000, true)
.done(function () {
// set up epol section with data
debugger;
})
.fail(function () {
// set up epol section for failure
debugger;
}))
).done(function (ebill, epol) {
// Determine whether ebill and epol succeeded or failed.
// You can also throw an error here using ebill or epol's reason,
// which gets you the error handling you're used to.
});
好吧,看来答案是否。相反,我必须手动管理自己的承诺/延期。
这是我最终使用的代码模式:
var callSvc = function (svcName, sleep, shouldFail) {
return $.ajax{...};
}
callSvc("sync", 0, true)
.then(function (result) {
var ebillPromise = $.Deferred();
var epolPromise = $.Deferred();
callSvc("ebill", 4000, false)
.then(function (data) {
// ebill success
debugger;
ebillPromise.resolve();
}, function () {
// ebill fail
debugger;
ebillPromise.resolve();
});
callSvc("epol", 2000, true)
.then(function (data) {
// epol success
debugger;
epolPromise.resolve();
}, function () {
// epol fail
debugger;
epolPromise.resolve();
});
return $.when(
ebillPromise,
epolPromise
)
}).fail(function () {
debugger;
}).always(function () {
// unblock the screen
debugger;
});
这是有效的,因为我的承诺永远不会被“拒绝”,所以我的 $.when() 会等待。
但是如果我们可以告诉 JQuery 等待,那就太好了。也许是一个“$.reallyWait()”函数......? :)
感谢@JeffBowman 和@bhmahler 让我指明了正确的方向!