为了账号安全,请及时绑定邮箱和手机立即绑定

在异步函数中等待多个承诺,无论如何都会抛出 try catch throws

在异步函数中等待多个承诺,无论如何都会抛出 try catch throws

PIPIONE 2022-12-02 15:47:38
我不明白为什么不抛出以下代码:const main = async () => {    const Stop = (time) => new Promise((resolve) => setTimeout(resolve, time))    try {        const p1 = Stop(500).then(() => { throw new Error('Error ocurred') })        const p2 = Stop(1000)        await p1        await p2    } catch (err) {        console.log('error catched')    }}main()但是每当我颠倒 p1 和 p2 承诺的顺序时,就像这样:const main = async () => {    const Stop = (time) => new Promise((resolve) => setTimeout(resolve, time))    try {        const p1 = Stop(500).then(() => { throw new Error('Error ocurred') })        const p2 = Stop(1000)        await p2        await p1    } catch (err) {        console.log('error catched')    }}main()然后抛出一个未捕获的异常。我认为在没有 .catch 函数的情况下执行这样的并发任务是危险的,但我认为 try catch 中的异步代码永远不会抛出。为什么不是这样呢?
查看完整描述

3 回答

?
莫回无

TA贡献1865条经验 获得超7个赞

首先,让我们退后一步,一起删除等待:


const main = async () => {


    const Stop = (time) => new Promise((resolve) => setTimeout(resolve, time))


    try {

        const p1 = Stop(500).then(() => { throw new Error('Error ocurred') })

        const p2 = Stop(1000)

    } catch (err) {

        console.log('error catched')

    

}


main()

我们得到一个未捕获的(承诺的)错误。这是预期的,因为 try/catch 不应该处理 Promise 拒绝。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#Description

await 表达式导致异步函数执行暂停,直到 Promise 被解决(即完成或拒绝),并在完成后恢复执行异步函数。恢复时,await 表达式的值是已完成的 Promise 的值。

如果 Promise 被拒绝,则 await 表达式会抛出被拒绝的值。

因此,如果我们希望 try/catch 处理 Promise 拒绝,我们需要记住两件事:

  1. 我们需要调用await以便当 Promise 被拒绝时表达式将抛出(避免未捕获(在 Promise 中)错误)

  2. 我们必须await在 Promise 拒绝发生之前调用

我们可以通过添加我们的第一个 await 来看到这一点:

const main = async () => {


    const Stop = (time) => new Promise((resolve) => setTimeout(resolve, time))


    try {

        const p1 = Stop(500).then(() => { throw new Error('Error ocurred') })

        const p2 = Stop(1000)


        await p1

    } catch (err) {

        console.log('error catched')

    }

}


main()

现在,await一旦 Promise 拒绝,这将抛出并且我们避免了 Uncaught (in Promise) Error。


但是如果我们添加await p2before await p1,调用p1 Promise期间await p2和之前的拒绝await p1。try/catch 不能及时工作,我们无法正确处理 Promise 拒绝:


const main = async () => {


    const Stop = (time) => new Promise((resolve) => setTimeout(resolve, time))


    try {

        const p1 = Stop(500).then(() => { throw new Error('Error ocurred') })

        const p2 = Stop(1000)


        await p2

        await p1

    } catch (err) {

        console.log('error catched')

    }

}


main()


我们可以通过改变时间来进一步观察 await 的这个关键序列,以便及时await p2恢复函数的执行以await p1等待被调用,从而使 try/catch 等待await p1抛出。


const main = async () => {


    const Stop = (time) => new Promise((resolve) => setTimeout(resolve, time))


    try {

        // Increased the time for p1 so the Promise resolves after p2 Promise resolves

        const p1 = Stop(1500).then(() => { throw new Error('Error ocurred') })

        const p2 = Stop(1000)


        await p2

        await p1

    } catch (err) {

        console.log('error catched')

    }

}


main()


我建议使用Promise.all:


更容易捕捉那些烦人的错误

避免每次使用 await 时多次暂停(这不是您的代码片段的问题,因为p1 Promise和p2 Promise正在“并行”运行,但这是代码中常见的问题)

const main = async () => {


    const Stop = (time) => new Promise((resolve) => setTimeout(resolve, time))


    try {

        const p1 = Stop(500).then(() => { throw new Error('Error ocurred') })

        const p2 = Stop(1000)


        await Promise.all([p2, p1])

    } catch (err) {

        console.log('error catched')

    }

}


main()

查看完整回答
反对 回复 2022-12-02
?
慕尼黑5688855

TA贡献1848条经验 获得超2个赞

我稍微修改了您的代码,它按预期工作。


const main = async () => {


const Stop = (time) => new Promise((resolve) => 

  setTimeout(resolve, time) )



try {

    const p1 = new Stop(500).then(() => { throw new Error('Error ocurred') })

    const p2 = new Stop(1000)


    await p2

    await p1

} catch (err) {

    console.log('error catched')

}} 

main()

我的理解是 Stop 之前指的是同一个实例,当我使用 new 关键字时,它创建了 2 个单独的实例来解决问题


查看完整回答
反对 回复 2022-12-02
?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

问题在于 async/await 旨在按时间启动异步任务并等待其执行,而在您的代码片段中您同时启动两个异步任务。如果在等待一个任务执行完成时另一个任务抛出,你会得到Uncaught (in promise) Error.


async/await 的一个很好的用法如下:


const main = async() => {


  const Stop = (time) => new Promise((resolve) => setTimeout(resolve, time));


  try {

    const p1 = await Stop(500).then(() => { throw new Error('Error ocurred') });

    const p2 = await Stop(1000);

  } catch (err) {

    console.log('caught:', err.message)

  }

}


main()


但是这两个任务是顺序执行的。处理更多并发异步任务的正确方法是Promise.all:


const main = async() => new Promise((resolve, reject) => {


  const Stop = (time) => new Promise((resolve) => setTimeout(resolve, time));


  const p1 = Stop(1000).then(() => {

    throw new Error('Error ocurred')

  });

  const p2 = Stop(3000);


  Promise.all([p1, p2]).then(resolve).catch(reject);

});


const parent = async() => {

  const start = new Date().getTime();

  try {

    console.log(await main());

  } catch (err) {

    console.log("caught:", err.message, "after:", new Date().getTime() - start, "ms");

  }

};


parent();


查看完整回答
反对 回复 2022-12-02
  • 3 回答
  • 0 关注
  • 73 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信