如何处理这个 promise.all 情况?

huangapple go评论68阅读模式
英文:

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) =&gt; {
        setTimeout(() =&gt; {
            reject(new TimeoutError(&quot;timeout&quot;));
        }, 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 === &quot;fulfilled&quot; &amp;&amp; result2.status === &quot;fulfilled&quot;) {
        // Both promises were fulfilled, see `result1.value` and `result2.value`
    } else if (result1.status === &quot;fulfilled&quot;) {
        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 === &quot;fulfilled&quot;) {
        // 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) =&gt; {
        setTimeout(() =&gt; {
            if (fulfill) {
                resolve(&quot;1 - OK&quot;);
            } else {
                reject(new Error(&quot;1 - failed&quot;));
            }
        }, ms);
    });
}

function f2(ms, fulfill) {
    return new Promise((resolve, reject) =&gt; {
        setTimeout(() =&gt; {
            if (fulfill) {
                resolve(&quot;2 - OK&quot;);
            } else {
                reject(new Error(&quot;2 - failed&quot;));
            }
        }, ms);
    });
}

class TimeoutError extends Error {}

function timeout(ms) {
    return new Promise((resolve, reject) =&gt; {
        setTimeout(() =&gt; {
            reject(new TimeoutError(&quot;timeout&quot;));
        }, 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 === &quot;fulfilled&quot; &amp;&amp; result2.status === &quot;fulfilled&quot;) {
        console.log(`Both promises were fulfilled:`);
        console.log(`result1.value = ${result1.value}`);
        console.log(`result2.value = ${result2.value}`);
    } else if (result1.status === &quot;fulfilled&quot;) {
        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 === &quot;fulfilled&quot;) {
        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) =&gt; {
        console.error(`Unexpected error in test: ${error.stack ?? String(error)}`);
    });
}

const onClick = (id, fn) =&gt; document.getElementById(id).addEventListener(&quot;click&quot;, fn);

onClick(&quot;both-fulfill&quot;,     () =&gt; test(&quot;Both Fulfill&quot;, 100, true, 150, true, 200));
onClick(&quot;first-fulfills&quot;,   () =&gt; test(&quot;First Fulfills&quot;, 100, true, 150, false, 200));
onClick(&quot;second-times-out&quot;, () =&gt; test(&quot;Second Times Out&quot;, 100, true, 250, true, 200));
onClick(&quot;second-fulfills&quot;,  () =&gt; test(&quot;Second Fulfills&quot;, 100, false, 150, true, 200));
onClick(&quot;both-reject&quot;,      () =&gt; test(&quot;Both Reject&quot;, 100, false, 150, false, 200));

<!-- language: lang-html -->

&lt;input type=&quot;button&quot; id=&quot;both-fulfill&quot; value=&quot;Both Fulfill&quot;&gt;
&lt;input type=&quot;button&quot; id=&quot;first-fulfills&quot; value=&quot;First Fulfills&quot;&gt;
&lt;input type=&quot;button&quot; id=&quot;second-times-out&quot; value=&quot;Second Times Out&quot;&gt;
&lt;input type=&quot;button&quot; id=&quot;second-fulfills&quot; value=&quot;Second Fulfills&quot;&gt;
&lt;input type=&quot;button&quot; id=&quot;both-reject&quot; value=&quot;Both Reject&quot;&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年1月6日 15:12:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75027986.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定