未兑现的承诺否决?

时间:2018-11-10 21:57:44

标签: javascript promise async-await

This example (repl.it)(来自this answer)在我看来,它遵循了有关承诺的所有规则。但是运行它会记录有关未处理的诺言拒绝的异常以及相关的控制台消息。 (在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()

1 个答案:

答案 0 :(得分:7)

问题在于,在rej调用被拒绝的那一点上,解释器尚未到达await符合rej创建的诺言的行,因此被拒绝的Promise就是被拒绝的Promise,而不是当前线程正在await正在

的一个Promise:

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

因此,其行为与在没有catch处理程序的情况下声明被拒绝的Promise相同。 (如果Promise抛出的错误在Promise拒绝的地方被async编辑,则会在await函数中捕获错误-否则,只会导致处于未处理的承诺拒绝中。)

我建议您在await的同一时刻声明承诺:

const data1 = await res(3000)

(注意:以上方法的计时与原始代码不同)

或对所有Promise使用await Promise.all,这意味着解释器当前Promise正在await处将尽快抛出(从而进入catch块) 一个承诺被拒绝:

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

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

要在三个Promise进行时进行其他工作,并从这些Promise以及主线程中捕获错误,请将第四项传递给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()