Необработанное обещание отказа? - PullRequest
0 голосов
/ 11 ноября 2018

Этот пример (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()

1 Ответ

0 голосов
/ 11 ноября 2018

Проблема в том, что в момент отклонения вызова rej интерпретатор еще не дошел до строки, которая await является обещанием, созданным rej, поэтому отклоненное обещание - это просто отклоненное Обещание, а не Обещание, что текущий поток await ing :

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. (Ошибки, выданные Обещаниями, будут обнаружены в функции async, только если они await ed в точке, в которой Обещание отклоняет - в противном случае это просто приведет к необработанному отклонению обещания .)

Я бы предложил объявить Обещания в тот же момент, что и вы await: 1018 *

const data1 = await res(3000)

(примечание: время вышеописанного метода не будет таким же, как у исходного кода)

или используйте await Promise.all для всех Обещаний, что означает, что Promise переводчик в настоящий момент await ing сгенерирует (и тем самым войдет в блок catch), как только one из Обещания отклоняются:

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