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

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

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:

  1. class TimeoutError extends Error {}
  2. function timeout(ms) {
  3. return new Promise((resolve, reject) => {
  4. setTimeout(() => {
  5. reject(new TimeoutError("timeout"));
  6. }, ms);
  7. });
  8. }
  9. async function test() {
  10. const p1 = // ...get the first promise...
  11. const p2 = // ...get the second promise...
  12. // Wait for the first to settle and the second to either settle or time out
  13. const [result1, result2] = await Promise.allSettled([
  14. p1,
  15. Promise.race([
  16. p2,
  17. timeout(150 /* or whatever, value in milliseconds */)
  18. ])
  19. ]);
  20. // See what happened
  21. if (result1.status === "fulfilled" && result2.status === "fulfilled") {
  22. // Both promises were fulfilled, see `result1.value` and `result2.value`
  23. } else if (result1.status === "fulfilled") {
  24. if (result2.reason instanceof TimeoutError) {
  25. // The first promise was fulfilled, the second timed out
  26. } else {
  27. // The first promise was fulfilled, the second was rejected
  28. }
  29. } else if (result2.status === "fulfilled") {
  30. // First promise was rejected, second was fulfilled
  31. } else {
  32. // Both promises were rejected, see `result1.reason` and `result2.reason`
  33. }
  34. }

Live Example:

  1. <input type="button" id="both-fulfill" value="Both Fulfill">
  2. <input type="button" id="first-fulfills" value="First Fulfills">
  3. <input type="button" id="second-times-out" value="Second Times Out">
  4. <input type="button" id="second-fulfills" value="Second Fulfills">
  5. <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:

  1. class TimeoutError extends Error {}
  2. function timeout(ms) {
  3. return new Promise((resolve, reject) =&gt; {
  4. setTimeout(() =&gt; {
  5. reject(new TimeoutError(&quot;timeout&quot;));
  6. }, ms);
  7. });
  8. }
  9. async function test() {
  10. const p1 = // ...get the first promise...
  11. const p2 = // ...get the second promise...
  12. // Wait for the first to settle and the second to either settle or time out
  13. const [result1, result2] = await Promise.allSettled([
  14. p1,
  15. Promise.race([
  16. p2,
  17. timeout(150 /* or whatever, value in milliseconds */)
  18. ])
  19. ]);
  20. // See what happened
  21. if (result1.status === &quot;fulfilled&quot; &amp;&amp; result2.status === &quot;fulfilled&quot;) {
  22. // Both promises were fulfilled, see `result1.value` and `result2.value`
  23. } else if (result1.status === &quot;fulfilled&quot;) {
  24. if (result2.reason instanceof TimeoutError) {
  25. // The first promise was fulfilled, the second timed out
  26. } else {
  27. // The first promise was fulfilled, the second was rejected
  28. }
  29. } else if (result2.status === &quot;fulfilled&quot;) {
  30. // First promise was rejected, second was fulfilled
  31. } else {
  32. // Both promises were rejected, see `result1.reason` and `result2.reason`
  33. }
  34. }

Live Example:

<!-- begin snippet: js hide: true console: true babel: false -->

<!-- language: lang-js -->

  1. function f1(ms, fulfill) {
  2. return new Promise((resolve, reject) =&gt; {
  3. setTimeout(() =&gt; {
  4. if (fulfill) {
  5. resolve(&quot;1 - OK&quot;);
  6. } else {
  7. reject(new Error(&quot;1 - failed&quot;));
  8. }
  9. }, ms);
  10. });
  11. }
  12. function f2(ms, fulfill) {
  13. return new Promise((resolve, reject) =&gt; {
  14. setTimeout(() =&gt; {
  15. if (fulfill) {
  16. resolve(&quot;2 - OK&quot;);
  17. } else {
  18. reject(new Error(&quot;2 - failed&quot;));
  19. }
  20. }, ms);
  21. });
  22. }
  23. class TimeoutError extends Error {}
  24. function timeout(ms) {
  25. return new Promise((resolve, reject) =&gt; {
  26. setTimeout(() =&gt; {
  27. reject(new TimeoutError(&quot;timeout&quot;));
  28. }, ms);
  29. });
  30. }
  31. async function example(ms1, fulfill1, ms2, fulfill2, msTimeout) {
  32. const p1 = f1(ms1, fulfill1);
  33. const p2 = f2(ms2, fulfill2);
  34. // Wait for the first to settle and the second to either settle or time out
  35. const [result1, result2] = await Promise.allSettled([
  36. p1,
  37. Promise.race([p2, timeout(msTimeout)])
  38. ]);
  39. // See what happened
  40. if (result1.status === &quot;fulfilled&quot; &amp;&amp; result2.status === &quot;fulfilled&quot;) {
  41. console.log(`Both promises were fulfilled:`);
  42. console.log(`result1.value = ${result1.value}`);
  43. console.log(`result2.value = ${result2.value}`);
  44. } else if (result1.status === &quot;fulfilled&quot;) {
  45. if (result2.reason instanceof TimeoutError) {
  46. console.log(`The first promise was fulfilled, the second timed out`);
  47. console.log(`result1.value = ${result1.value}`);
  48. console.log(`result2 was a timeout`);
  49. } else {
  50. console.log(`The first promise was fulfilled, the second was rejected`);
  51. console.log(`result1.value = ${result1.value}`);
  52. console.log(`result2.reason = ${result2.reason}`);
  53. }
  54. } else if (result2.status === &quot;fulfilled&quot;) {
  55. console.log(`The first promise was rejected, second was fulfilled`);
  56. console.log(`result1.reason = ${result1.reason}`);
  57. console.log(`result2.value = ${result2.value}`);
  58. } else {
  59. // Both promises were rejected, see `result1.reason` and `result2.reason`
  60. console.log(`The first promise was rejected, second was fulfilled`);
  61. console.log(`result1.reason = ${result1.reason}`);
  62. console.log(`result2.rason = ${result2.reason}`);
  63. }
  64. }
  65. function test(label, ms1, fulfill1, ms2, fulfill2, msTimeout) {
  66. console.log(`${label}:`);
  67. example(ms1, fulfill1, ms2, fulfill2, msTimeout)
  68. .catch((error) =&gt; {
  69. console.error(`Unexpected error in test: ${error.stack ?? String(error)}`);
  70. });
  71. }
  72. const onClick = (id, fn) =&gt; document.getElementById(id).addEventListener(&quot;click&quot;, fn);
  73. onClick(&quot;both-fulfill&quot;, () =&gt; test(&quot;Both Fulfill&quot;, 100, true, 150, true, 200));
  74. onClick(&quot;first-fulfills&quot;, () =&gt; test(&quot;First Fulfills&quot;, 100, true, 150, false, 200));
  75. onClick(&quot;second-times-out&quot;, () =&gt; test(&quot;Second Times Out&quot;, 100, true, 250, true, 200));
  76. onClick(&quot;second-fulfills&quot;, () =&gt; test(&quot;Second Fulfills&quot;, 100, false, 150, true, 200));
  77. onClick(&quot;both-reject&quot;, () =&gt; test(&quot;Both Reject&quot;, 100, false, 150, false, 200));

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

  1. &lt;input type=&quot;button&quot; id=&quot;both-fulfill&quot; value=&quot;Both Fulfill&quot;&gt;
  2. &lt;input type=&quot;button&quot; id=&quot;first-fulfills&quot; value=&quot;First Fulfills&quot;&gt;
  3. &lt;input type=&quot;button&quot; id=&quot;second-times-out&quot; value=&quot;Second Times Out&quot;&gt;
  4. &lt;input type=&quot;button&quot; id=&quot;second-fulfills&quot; value=&quot;Second Fulfills&quot;&gt;
  5. &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:

确定