等待多个并发等待操作 [英] Waiting for more than one concurrent await operation

查看:138
本文介绍了等待多个并发等待操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何更改以下代码,以便同时触发异步操作并有机会同时运行?

How can I change the following code so that both async operations are triggered and given an opportunity to run concurrently?

const value1 = await getValue1Async();
const value2 = await getValue2Async();
// use both values

我需要做这样的事吗?

const p1 = getValue1Async();
const p2 = getValue2Async();
const value1 = await p1;
const value2 = await p2;
// use both values


推荐答案

TL; DR



请勿在获得承诺的问题中使用该模式,然后单独等待它们;相反,使用 Promise.all (至少目前为止):

TL;DR

Don't use the pattern in the question where you get the promises, and then separately wait on them; instead, use Promise.all (at least for now):

const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);

虽然您的解决方案 并行运行这两项操作但它没有'如果两个承诺都拒绝,则正确处理拒绝。

While your solution does run the two operations in parallel, it doesn't handle rejection properly if both promises reject.

您的解决方案并行运行它们,但始终在等待第二个之前等待第一个完成。 如果您只想启动它们,并行运行它们,并获得两个结果,就可以了。 (不,它不是,继续阅读......)请注意,如果第一个完成(比方说)五秒钟完成而第二个故障在一秒钟内完成,那么您的代码将等待整整五秒钟然后失败。

Your solution runs them in parallel, but always waits for the first to finish before waiting for the second. If you just want to start them, run them in parallel, and get both results, it's just fine. (No, it isn't, keep reading...) Note that if the first takes (say) five seconds to complete and the second fails in one second, your code will wait the full five seconds before then failing.

可悲的是,当前没有 await 语法进行并行等待,因此您有列出的尴尬,或者 Promise.all 。 (有讨论了 await.all 或类似的,但也许有一天。)

Sadly, there isn't currently await syntax to do a parallel wait, so you have the awkwardness you listed, or Promise.all. (There's been discussion of await.all or similar, though; maybe someday.)

Promise.all 版本是:

const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);

...这更简洁,也不等待第一次操作完成第二个快速失败(例如,在我上面的五秒钟/一秒钟的例子中,上面将在一秒内拒绝而不是等待五秒钟)。另请注意,使用原始代码,如果第二个承诺在第一个承诺解决之前拒绝,您可能会在控制台中出现未处理的拒绝错误(您当前使用的是Chrome v61),尽管该错误可能是虚假的(因为您,最终,处理拒绝)。但是如果两个承诺拒绝,你将得到一个真正的未处理拒绝错误,因为控制流永远不会达到 const value2 = await p2; 因此p2拒绝永远不会被处理。

...which is more concise, and also doesn't wait for the first operation to complete if the second fails quickly (e.g., in my five seconds / one second example above, the above will reject in one second rather than waiting five). Also note that with your original code, if the second promise rejects before the first promise resolves, you may well get a "unhandled rejection" error in the console (you do currently with Chrome v61), although that error is arguably spurious (because you do, eventually, handle the rejection). But if both promises reject, you'll get a genuine unhandled rejection error because the flow of control never reaches const value2 = await p2; and thus the p2 rejection is never handled.

未处理的拒绝是一件坏事™(如此之多,以至于很快,NodeJS将在真正未处理的拒绝中止流程,就像未处理的异常一样;—因为它们就是这样),所以最好避免在你的问题中获得承诺然后等待 it模式。

Unhandled rejections are a Bad Thing™ (so much so that soon, NodeJS will abort the process on truly unhandled rejections, just like unhandled exceptions — because that's what they are), so best to avoid the "get the promise then await it" pattern in your question.

这是一个失败案例中时间差异的例子(使用500毫秒和100毫秒而不是5秒和1秒),也可能是虚假的未处理拒绝错误(打开真实浏览器控制台看到它):

Here's an example of the difference in timing in the failure case (using 500ms and 100ms rather than 5 seconds and 1 second), and possibly also the arguably-spurious unhandled rejection error (open the real browser console to see it):

const getValue1Async = () => {
  return new Promise(resolve => {
    setTimeout(resolve, 500, "value1");
  });
};
const getValue2Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 100, "error");
  });
};

// This waits the full 500ms before failing, because it waits
// on p1, then on p2
(async () => {
  try {
    console.time("separate");
    const p1 = getValue1Async();
    const p2 = getValue2Async();
    const value1 = await p1;
    const value2 = await p2;
  } catch (e) {
    console.error(e);
  }
  console.timeEnd("separate");
})();

// This fails after just 100ms, because it doesn't wait for p1
// to finish first, it rejects as soon as p2 rejects
setTimeout(async () => {
  try {
    console.time("Promise.all");
    const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);
  } catch (e) {
    console.timeEnd("Promise.all", e);
  }
}, 1000);

Open the real browser console to see the unhandled rejection error.

这里我们拒绝 p1 p2 ,导致 p2上的非虚假未处理拒绝错误

And here we reject both p1 and p2, resulting in a non-spurious unhandled rejection error on p2:

const getValue1Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 500, "error1");
  });
};
const getValue2Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 100, "error2");
  });
};

// This waits the full 500ms before failing, because it waits
// on p1, then on p2
(async () => {
  try {
    console.time("separate");
    const p1 = getValue1Async();
    const p2 = getValue2Async();
    const value1 = await p1;
    const value2 = await p2;
  } catch (e) {
    console.error(e);
  }
  console.timeEnd("separate");
})();

// This fails after just 100ms, because it doesn't wait for p1
// to finish first, it rejects as soon as p2 rejects
setTimeout(async () => {
  try {
    console.time("Promise.all");
    const [value1, value2] = await Promise.all([getValue1Async(), getValue2Async()]);
  } catch (e) {
    console.timeEnd("Promise.all", e);
  }
}, 1000);

Open the real browser console to see the unhandled rejection error.

在评论中你问过:


附带问题:以下部队将等待(并放弃结果)等待p1&&等待p2

这与原始代码的承诺拒绝问题相同:它会等到 p1 即使 p2 先前拒绝,也会结算;如果 p2 p1 结算之前拒绝,它可能会产生可论证的虚假未处理拒绝错误;如果 p1 p2 拒绝,则会产生真正的未处理拒绝错误(因为 p2 永远不会处理拒绝。

This has the same issues around promise rejection as your original code: It will wait until p1 resolves even if p2 rejects earlier; it may generate an arguably-spurious unhandled rejection error if p2 rejects before p1 resolves; and it generates a genuine unhandled rejection error if both p1 and p2 reject (because p2's rejection is never handled).

这是 p1 解决的情况code> p2 拒绝:

Here's the case where p1 resolves and p2 rejects:

const getValue1Async = () => {
  return new Promise(resolve => {
    setTimeout(resolve, 500, false);
  });
};
const getValue2Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 100, "error");
  });
};

(async () => {
  try {
    const p1 = getValue1Async();
    const p2 = getValue2Async();
    console.log("waiting");
    await p1 && await p2;
  } catch (e) {
    console.error(e);
  }
  console.log("done waiting");
})();

Look in the real console (for the unhandled rejection error).

...并且两者都拒绝:

...and where both reject:

const getValue1Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 500, "error1");
  });
};
const getValue2Async = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 100, "error2");
  });
};

(async () => {
  try {
    const p1 = getValue1Async();
    const p2 = getValue2Async();
    console.log("waiting");
    await p1 && await p2;
  } catch (e) {
    console.error(e);
  }
  console.log("done waiting");
})();

Look in the real console (for the unhandled rejection error).

这篇关于等待多个并发等待操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆