蓝鸟:等待一个承诺来解决
Bluebird: Waiting for one promise to settle
冒着听起来很愚蠢的风险:等待一个 promise 结算的最有效方法是什么?假设我有承诺 A,我想创建承诺 B。B 的实现不取决于 A 的最终值。即使 A 被拒绝,它也应该继续。但是,在 A 以一种或另一种方式解决之前,该过程不应开始。
我目前拥有的内容如下所示:
var prevResult;
function doStuff() {
if (prevResult) {
prevResult = promise.settle([ prevResult ]).then(function() {
return doStuff();
})
} else {
prevResult = updateDB().finally(function() {
prevResult = null;
});
}
return prevResult;
}
代码有点不明显。我也有点担心将 settle() 中的一堆承诺链接在一起,看看它是如何执行不那么琐碎的协调的。似乎应该有一个更简单的方法来做到这一点。
您可以使用 finally,无论先前承诺的结果如何都会触发。
以下代码来自bluebird github doco。
function ajaxGetAsync(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest;
xhr.addEventListener("error", reject);
xhr.addEventListener("load", resolve);
xhr.open("GET", url);
xhr.send(null);
}).finally(function() {
$("#ajax-loader-animation").hide();
});
}
假设您有两个承诺返回函数 doAsync_A
和 doAsync_B
。
下面的表达式会执行doAsync_A
,等待它的promise结算(成为履行或拒绝),然后执行doAsync_B
Promise.settle([doAsync_A()]).then(doAsync_B);
doAsync_B
将传递一个 "PromiseInspection" 数组(这里是单个元素)。如有必要,您可以测试doAsync_A
是成功还是失败。
function doAsync_B(results) {
var r = results[0];
if (r.isFulfilled()) { // check if was successful
console.log(r.value()); // the promise's return value
} else if (r.isRejected()) { // check if the read failed
console.log(r.reason()); // the promise's rejection reason
}
}
我认为最好的方法是将 doStuff
同时作为履行和拒绝处理程序:
prevResult = prevResult.then(function() { return doStuff(); },
function() { return doStuff(); });
或者
prevResult = prevResult.catch(ignore).then(function() { return doStuff(); });
您似乎正在尝试对 updateDB
操作进行排队。我建议不要将 prevResult
重置为 null
,而只是让它成为所有排队操作完成后履行的承诺。看看 this example.
最近,.reflect
被引入作为更灵活的 .settle
和更好的抽象。您的用例听起来很容易 .reflect
A.reflect().then(function(){
return doSomethingThatReturnsB();
});
您的代码的完整示例:
var prevResult;
function doStuff() {
prevResult = Promise.resolve(prevResult).reflect().then(function(){
return updateDB();
});
return prevResult;
}
冒着听起来很愚蠢的风险:等待一个 promise 结算的最有效方法是什么?假设我有承诺 A,我想创建承诺 B。B 的实现不取决于 A 的最终值。即使 A 被拒绝,它也应该继续。但是,在 A 以一种或另一种方式解决之前,该过程不应开始。
我目前拥有的内容如下所示:
var prevResult;
function doStuff() {
if (prevResult) {
prevResult = promise.settle([ prevResult ]).then(function() {
return doStuff();
})
} else {
prevResult = updateDB().finally(function() {
prevResult = null;
});
}
return prevResult;
}
代码有点不明显。我也有点担心将 settle() 中的一堆承诺链接在一起,看看它是如何执行不那么琐碎的协调的。似乎应该有一个更简单的方法来做到这一点。
您可以使用 finally,无论先前承诺的结果如何都会触发。
以下代码来自bluebird github doco。
function ajaxGetAsync(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest;
xhr.addEventListener("error", reject);
xhr.addEventListener("load", resolve);
xhr.open("GET", url);
xhr.send(null);
}).finally(function() {
$("#ajax-loader-animation").hide();
});
}
假设您有两个承诺返回函数 doAsync_A
和 doAsync_B
。
下面的表达式会执行doAsync_A
,等待它的promise结算(成为履行或拒绝),然后执行doAsync_B
Promise.settle([doAsync_A()]).then(doAsync_B);
doAsync_B
将传递一个 "PromiseInspection" 数组(这里是单个元素)。如有必要,您可以测试doAsync_A
是成功还是失败。
function doAsync_B(results) {
var r = results[0];
if (r.isFulfilled()) { // check if was successful
console.log(r.value()); // the promise's return value
} else if (r.isRejected()) { // check if the read failed
console.log(r.reason()); // the promise's rejection reason
}
}
我认为最好的方法是将 doStuff
同时作为履行和拒绝处理程序:
prevResult = prevResult.then(function() { return doStuff(); },
function() { return doStuff(); });
或者
prevResult = prevResult.catch(ignore).then(function() { return doStuff(); });
您似乎正在尝试对 updateDB
操作进行排队。我建议不要将 prevResult
重置为 null
,而只是让它成为所有排队操作完成后履行的承诺。看看 this example.
最近,.reflect
被引入作为更灵活的 .settle
和更好的抽象。您的用例听起来很容易 .reflect
A.reflect().then(function(){
return doSomethingThatReturnsB();
});
您的代码的完整示例:
var prevResult;
function doStuff() {
prevResult = Promise.resolve(prevResult).reflect().then(function(){
return updateDB();
});
return prevResult;
}