英文:
How to handle this promise.all case?
问题
我们有一个并行的Promise调用:
promise.all([p1, p2]).then().catch()
这里p1和p2是两个不同的Promise调用。
- p1 - 对某些条件拒绝并显示e1
- p2 - 对某些条件拒绝并显示e2
- p1 - 解决然后执行某些操作
- p2 - 不解决
p1和p2的拒绝条件不同。
如果p1和p2都拒绝,我们显示e2。
现在假设两者都拒绝,但是p1先拒绝,如何处理并显示e2?
p1对p2的完成时间 > p90,但在p1比p2更早发生的边缘情况下,如何处理这个问题?
尝试使用promise.allSettled,但它有其他问题,其中p2在.then块运行了2次后执行(结果中有2个Promise和相应的数组元素)。
我们已经尝试了多种方法,在p1失败时使用特定的错误消息解决,但不起作用。
英文:
We have a parallel promise call:-
promise.all([p1,p2]).then().catch()
here p1,p2 are 2 different promise calls .
- p1 - reject for some condition and show e1
- p2 - reject for some condition and show e2
- p1 - resolve then do something
- p2 - do not resolve
p1,p2 reject conditions are different .
If p1,p2 both reject , we show e2
Now suppose both reject but p1 rejects first , how to handle this and show e2 ?
p90 for p1 > p90 for p2 but there can be the edge cases if p1 happens earlier than p2 , hence the query .
Tried using promise.allSettled but it had other issues where p2 executed after the .then block ran for 2 times (there were 2 promise and corresponding array elements in the results ).
We have tried multiple things , resolving with a particular error message in case of p1 failure but it does not work .
答案1
得分: 2
(Preface: Promise terminology can be confusing and most people use it incorrectly. My blog post on terminology may be a useful read.)
You were right to look at Promise.allSettled
. If you want to do X when one promise is fulfilled and another is rejected, that's the way to go; you get an array of the results, rather than Promise.all
's behavior of short-circuiting if any of the input promises is rejected.
p2 - do not resolve
It's not clear what you mean by that, but if you mean you need to do something if p2
doesn't settle (get fulfilled or rejected) within a certain period of time, you probably want to use Promise.race
with a timeout promise.
Without code it's hard to help you, but here's an example of combining Promise.allSettled
with Promise.race
:
class TimeoutError extends Error {}
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new TimeoutError("timeout"));
}, ms);
});
}
async function test() {
const p1 = // ...get the first promise...
const p2 = // ...get the second promise...
// Wait for the first to settle and the second to either settle or time out
const [result1, result2] = await Promise.allSettled([
p1,
Promise.race([
p2,
timeout(150 /* or whatever, value in milliseconds */)
])
]);
// See what happened
if (result1.status === "fulfilled" && result2.status === "fulfilled") {
// Both promises were fulfilled, see `result1.value` and `result2.value`
} else if (result1.status === "fulfilled") {
if (result2.reason instanceof TimeoutError) {
// The first promise was fulfilled, the second timed out
} else {
// The first promise was fulfilled, the second was rejected
}
} else if (result2.status === "fulfilled") {
// First promise was rejected, second was fulfilled
} else {
// Both promises were rejected, see `result1.reason` and `result2.reason`
}
}
Live Example:
<input type="button" id="both-fulfill" value="Both Fulfill">
<input type="button" id="first-fulfills" value="First Fulfills">
<input type="button" id="second-times-out" value="Second Times Out">
<input type="button" id="second-fulfills" value="Second Fulfills">
<input type="button" id="both-reject" value="Both Reject">
(Note: The code snippets are in English as code is typically written in English.)
英文:
(Preface: Promise terminology can be confusing and most people use it incorrect. My blog post on terminology may be a useful read.)
You were right to look at Promise.allSettled
. If you want to do X when one promise is fulfilled and another is rejected, that's the way to go; you get an array of the results, rather than Promise.all
's behavior of short-circuiting if any of the input promises is rejected.
> p2 - do not resolve
It's not clear what you mean by that, but if you mean you need to do something if p2
doesn't settle (get fulfilled or rejected) within a certain period of time, you probably want to use Promise.race
with a timeout promise.
Without code it's hard to help you, but here's an example of combining Promise.allSettled
with Promise.race
:
class TimeoutError extends Error {}
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new TimeoutError("timeout"));
}, ms);
});
}
async function test() {
const p1 = // ...get the first promise...
const p2 = // ...get the second promise...
// Wait for the first to settle and the second to either settle or time out
const [result1, result2] = await Promise.allSettled([
p1,
Promise.race([
p2,
timeout(150 /* or whatever, value in milliseconds */)
])
]);
// See what happened
if (result1.status === "fulfilled" && result2.status === "fulfilled") {
// Both promises were fulfilled, see `result1.value` and `result2.value`
} else if (result1.status === "fulfilled") {
if (result2.reason instanceof TimeoutError) {
// The first promise was fulfilled, the second timed out
} else {
// The first promise was fulfilled, the second was rejected
}
} else if (result2.status === "fulfilled") {
// First promise was rejected, second was fulfilled
} else {
// Both promises were rejected, see `result1.reason` and `result2.reason`
}
}
Live Example:
<!-- begin snippet: js hide: true console: true babel: false -->
<!-- language: lang-js -->
function f1(ms, fulfill) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (fulfill) {
resolve("1 - OK");
} else {
reject(new Error("1 - failed"));
}
}, ms);
});
}
function f2(ms, fulfill) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (fulfill) {
resolve("2 - OK");
} else {
reject(new Error("2 - failed"));
}
}, ms);
});
}
class TimeoutError extends Error {}
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new TimeoutError("timeout"));
}, ms);
});
}
async function example(ms1, fulfill1, ms2, fulfill2, msTimeout) {
const p1 = f1(ms1, fulfill1);
const p2 = f2(ms2, fulfill2);
// Wait for the first to settle and the second to either settle or time out
const [result1, result2] = await Promise.allSettled([
p1,
Promise.race([p2, timeout(msTimeout)])
]);
// See what happened
if (result1.status === "fulfilled" && result2.status === "fulfilled") {
console.log(`Both promises were fulfilled:`);
console.log(`result1.value = ${result1.value}`);
console.log(`result2.value = ${result2.value}`);
} else if (result1.status === "fulfilled") {
if (result2.reason instanceof TimeoutError) {
console.log(`The first promise was fulfilled, the second timed out`);
console.log(`result1.value = ${result1.value}`);
console.log(`result2 was a timeout`);
} else {
console.log(`The first promise was fulfilled, the second was rejected`);
console.log(`result1.value = ${result1.value}`);
console.log(`result2.reason = ${result2.reason}`);
}
} else if (result2.status === "fulfilled") {
console.log(`The first promise was rejected, second was fulfilled`);
console.log(`result1.reason = ${result1.reason}`);
console.log(`result2.value = ${result2.value}`);
} else {
// Both promises were rejected, see `result1.reason` and `result2.reason`
console.log(`The first promise was rejected, second was fulfilled`);
console.log(`result1.reason = ${result1.reason}`);
console.log(`result2.rason = ${result2.reason}`);
}
}
function test(label, ms1, fulfill1, ms2, fulfill2, msTimeout) {
console.log(`${label}:`);
example(ms1, fulfill1, ms2, fulfill2, msTimeout)
.catch((error) => {
console.error(`Unexpected error in test: ${error.stack ?? String(error)}`);
});
}
const onClick = (id, fn) => document.getElementById(id).addEventListener("click", fn);
onClick("both-fulfill", () => test("Both Fulfill", 100, true, 150, true, 200));
onClick("first-fulfills", () => test("First Fulfills", 100, true, 150, false, 200));
onClick("second-times-out", () => test("Second Times Out", 100, true, 250, true, 200));
onClick("second-fulfills", () => test("Second Fulfills", 100, false, 150, true, 200));
onClick("both-reject", () => test("Both Reject", 100, false, 150, false, 200));
<!-- language: lang-html -->
<input type="button" id="both-fulfill" value="Both Fulfill">
<input type="button" id="first-fulfills" value="First Fulfills">
<input type="button" id="second-times-out" value="Second Times Out">
<input type="button" id="second-fulfills" value="Second Fulfills">
<input type="button" id="both-reject" value="Both Reject">
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论