当前位置: 首页 > 面试题库 >

等待多个并发等待操作

盖嘉庆
2023-03-14
问题内容

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

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(至少现在):

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

虽然您的解决方案 确实 并行运行这两个操作,但如果两个诺言都被拒绝,它就无法正确处理拒绝。

细节:

您的解决方案并行运行它们,但始终等待第一个完成,然后再等待第二个。 如果您只想启动它们,并行运行它们,并获得两个结果,那就很好了。
(不,不是,请继续阅读…) 请注意,如果第一个完成(例如)花了五秒钟,而第二个则在一秒钟内失败,那么您的代码将等待整整五秒钟,然后再失败。

遗憾的是,当前await没有并行等待的语法,因此您有列出的尴尬或Promise.all。(不过,有过await.all类似的讨论;也许有一天。)

Promise.all版本是:

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

…更加简洁,如果第二个操作很快失败,也不会等待第一个操作完成(例如,在我上面的五秒/一秒示例中,上面的操作将在一秒钟内拒绝,而不是等待五个)
。另请注意,使用原始代码,如果第二个承诺在第一个承诺解决之前被拒绝,您很可能在控制台中收到“未处理的拒绝”错误您目前使用Chrome v61;
更新:更新的 版本具有更有趣的行为,尽管该错误可以说是虚假的(因为您 这样做
,最终可以处理拒绝,因为该代码显然在一个async函数¹中,因此该函数将钩住拒绝并使其承诺与它一起被拒绝 **更新:
再次,[更改]。但是,如果两个诺言都被拒绝,您将得到真正的未处理的拒绝错误,因为控制流永远不会到达const value2 = await p2;,因此永远不会处理p2拒绝。

未处理的拒绝是Bad Thing™(以至于很快,Node.js就会在真正未处理的拒绝上终止流程,就像未处理的异常一样-
因为它们就是这样),因此最好避免“先得到承诺await”。问题中的模式。

这是一个故障情况下时间差异的示例(使用500ms和100ms而不是5秒和1秒),还可能是虚假的未处理拒绝错误(打开 真实的 浏览器控制台查看):

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.

在这里,我们同时拒绝p1p2,从而导致以下错误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.

在评论中,您询问:

附带问题:以下部队是否会同时等待(并丢弃结果)await p1 && await p2

关于承诺拒绝的问题与您的原始代码存在相同的问题:p1即使p2更早拒绝,它也会等到解决为止。如果在解决之前拒绝,则可能会产生可能是虚假的(
update:
或临时未处理的拒绝错误;并且如果和都拒绝,则会生成真正的未处理拒绝错误(因为从未处理过拒绝)。p2``p1``p1``p2``p2

p1解决和p2拒绝的情况如下:

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).

…而且两者都拒绝:

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).

¹ _“
…此代码显然在async函数中…”_在2017年编写此问题和答案时确实如此。从那以后,高层await发生了/正在发生。



 类似资料:
  • 问题内容: 如何更改以下代码,以触发两个异步操作并有机会同时运行? 我需要做这样的事情吗? 问题答案: TL; DR 不要在获得承诺的问题中使用模式,而是分别等待它们;而是使用(至少现在): 虽然您的解决方案 确实 并行运行这两个操作,但如果两个诺言都被拒绝,它就无法正确处理拒绝。 细节: 您的解决方案并行运行它们,但始终等待第一个完成,然后再等待第二个。 如果您只想启动它们,并行运行它们,并获得

  • 问题内容: 请考虑以下代码片段: 这是在小程序中添加一个标签,该标签显示了Worker线程的一些中间结果(使用发布/处理方法)。最后,标签从小程序的窗格中删除。我的问题是,如何创建多个标签,每个标签都有自己的Worker线程,并在完成标签后将其删除? 提前致谢。 更新: 我希望这可以澄清我的问题。我希望在所有工作人员都完成任务后立即删除所有标签,而不是在每个工作人员都完成之后立即删除。 更新2:

  • 请考虑以下代码片段: 下面是向小程序添加一个标签,该标签显示工作线程的一些中间结果(使用发布/处理方法)。最后,标签将从小程序的窗格中移除。我的问题是,我如何创建几个标签,每个标签都有自己的工作线程,并在全部完成后删除它们? 提前感谢。 更新: 我希望这能澄清我的问题。我希望在所有工人完成任务后,而不是在每个工人完成任务后立即移除所有标签。 更新2: 下面的代码似乎正在做我需要的事情。请评论我的做

  • 我想运行相同类型的任务(工作线程),但一次不超过一定数量的任务。当任务完成时,其结果是新任务的输入,然后可以启动该任务。 有没有好的方法可以在C 11中使用异步/未来范式来实现这一点? 乍一看,它看起来很简单,你只是生成多个任务: 然后,运行以获取任务的异步结果。 然而,这里的问题是,未来的对象必须存储在某种队列中并一个接一个地等待。但是,可以一遍又一遍地迭代未来的对象,检查它们中的任何一个是否准

  • 我可以让selenium webdriver“默认”等待它的每个操作执行吗?例如,设置任何“默认等待时间”,使其尝试每500毫秒点击每个元素10次?

  • 我正在尝试将数据库调用移出控制器,以清理并使其可测试。当它们在控制器中时,一切都会顺利进行。我将它们移出控制器,并添加了一个异步,以确保我们等待。否则,我将调用的中的函数。现在,一旦我使用async/await,控制器中的函数就会认为没有用户,因为它没有等待。 有几个关于异步等待的SO问题,但我没有找到一个解决我的问题。我确实验证了返回了我的用户,并添加了控制台日志来显示路径。 节点猫鼬异步等待似