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

我不明白为什么不抛出以下代码:


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 中的异步代码永远不会抛出。


为什么不是这样呢?


PIPIONE
浏览 168回答 3
3回答

莫回无

首先,让我们退后一步,一起删除等待: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#Descriptionawait 表达式导致异步函数执行暂停,直到 Promise 被解决(即完成或拒绝),并在完成后恢复执行异步函数。恢复时,await 表达式的值是已完成的 Promise 的值。如果 Promise 被拒绝,则 await 表达式会抛出被拒绝的值。因此,如果我们希望 try/catch 处理 Promise 拒绝,我们需要记住两件事:我们需要调用await以便当 Promise 被拒绝时表达式将抛出(避免未捕获(在 Promise 中)错误)我们必须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()

慕尼黑5688855

我稍微修改了您的代码,它按预期工作。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 个单独的实例来解决问题

鸿蒙传说

问题在于 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();
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript