未处理的承诺拒绝?

Our*_*rus 4 javascript promise async-await

这个例子(repl.it)(从这个答案)看起来像它遵循所有关于承诺的规则.然而,运行它会记录关于未处理的承诺拒绝与相关控制台消息的异常.(这也发生在FF,Chrome和Node v10中.)

try/catch块显然在那里并且包含被拒绝的承诺,所以发生了什么以及我将如何修复它?

async function example() {
  const start = Date.now()
  let i = 0
  function res(n) {
    const id = ++i
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve()
        console.log(`res #${id} called after ${n} milliseconds`, Date.now() - start)
      }, n)
    })
  }

  function rej(n) {
    const id = ++i
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject()
        console.log(`rej #${id} called after ${n} milliseconds`, Date.now() - start)
      }, n)
    })
  }

  try {
    const delay1 = res(3000)
    const delay2 = res(2000)
    const delay3 = rej(1000)

    const data1 = await delay1
    const data2 = await delay2
    const data3 = await delay3
  } catch (error) {
    console.log(`await finished`, Date.now() - start)
  }
}

example()
Run Code Online (Sandbox Code Playgroud)

Cer*_*nce 7

问题是,在rej调用拒绝的时候,解释器还没有得到一个await由创建的承诺的行rej,所以被拒绝的Promise就是那个,被拒绝的Promise,而不是当前线程的Promise是await荷兰国际集团:

try {
  const delay1 = res(3000)
  const delay2 = res(2000)
  const delay3 = rej(1000)

  const data1 = await delay1
  // The interpreter is paused on the line above when `rej` rejects
  const data2 = await delay2
  const data3 = await delay3
Run Code Online (Sandbox Code Playgroud)

因此,行为与在没有catch处理程序的情况下声明被拒绝的Promise相同.(由承诺引发的错误只会在被捕获async功能,如果他们await在处无极拒绝点 -否则,它只会导致未处理的承诺拒绝)

我建议你或者在同一点声明Promise await:

const data1 = await res(3000)
Run Code Online (Sandbox Code Playgroud)

(注意:上述方法的时间与原始代码不一样)

或使用await Promise.all对所有的承诺,这意味着Promise解释目前await荷兰国际集团将抛出(从而进入catch块)只要一个承诺的拒绝:

const [data1, data2, data3] = await Promise.all([
  res(3000),
  res(2000),
  rej(1000)
]);
Run Code Online (Sandbox Code Playgroud)

async function example() {
  const start = Date.now()
  let i = 0
  function res(n) {
    const id = ++i
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve()
        console.log(`res #${id} called after ${n} milliseconds`, Date.now() - start)
      }, n)
    })
  }
  
  function rej(n) {
    const id = ++i
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject()
        console.log(`rej #${id} called after ${n} milliseconds`, Date.now() - start)
      }, n)
    })
  }
  
  try {
    const [data1, data2, data3] = await Promise.all([
      res(3000),
      res(2000),
      rej(1000),
    ]);
  } catch (error) {
    console.log(`error caught: await finished`, Date.now() - start)
  }
}

example()
Run Code Online (Sandbox Code Playgroud)

做额外的工作,而三项承诺是持续的,并且赶上从这些承诺,以及在主线程错误,传递第四个项目的Promise.all,已经做了你想要做的额外工作的IIFE:

async function example() {
  const start = Date.now()
  let i = 0
  function res(n) {
    const id = ++i
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve()
        console.log(`res #${id} called after ${n} milliseconds`, Date.now() - start)
      }, n)
    })
  }
  
  function rej(n) {
    const id = ++i
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject()
        console.log(`rej #${id} called after ${n} milliseconds`, Date.now() - start)
      }, n)
    })
  }
  
  try {
    const [data1, data2, data3] = await Promise.all([
      res(3000),
      res(2000),
      rej(1000),
      (() => {
        console.log('doing work...');
      })()
    ]);
  } catch (error) {
    console.log(`error caught: await finished`, Date.now() - start)
  }
}

example()
Run Code Online (Sandbox Code Playgroud)