Обновление 2020 г .: Я обновил руководство, чтобы отразить, как изменилось сообщение в более поздних версиях Node.js, и также сократил сообщение. Если вы ищете старую версию, вы можете найти ее в Интернет-архиве.

Эта проблема

Если вы видите эту ошибку:

[UnhandledPromiseRejection: эта ошибка возникла либо из-за вызова асинхронной функции без блока catch, либо из-за отклонения обещания, которое не было обработано с помощью .catch (). Обещание отклонено по причине «…».] {Code: ERR_UNHANDLED_REJECTION ’}

то, скорее всего, вы делаете следующее:

  • Вы помещаете свой код в функцию async, чтобы использовать await вызовы
  • Одна из ваших awaited функций не работает (т.е. отклоняет обещание)
  • Вы получаете ошибку

Другая возможность состоит в том, что вы знаете, что вам нужно поймать отклоненное обещание. В этом случае может произойти следующее:

  • Вы помещаете свой код в функцию async, чтобы использовать await вызовы
  • Вы помещаете вызов await в блок try / catch или используете .catch ()
  • Функция awaited не работает (т.е. отклоняет обещание)
  • Вы throw ошибка в блоке catch для завершения сценария
  • Вы получаете ошибку

В первом случае ключом является эта часть сообщения об ошибке:

… отклонив обещание, которое не было обработано с помощью .catch ().

Решение простое: используйте .catch (), как указано в сообщении:

await returnsPromise().catch(e => { console.log(e) })

Или используйте блок try / catch:

try {
  await returnsPromise()
} catch (error) {
  console.log('That did not go well.')
}

Во втором случае ключевая часть такова:

бросание внутри асинхронной функции без блока catch

Не throw внутри async функции, не уловив!

Вы можете подумать, что предупреждение касается обещания, полученного от функции, которую вы ждали, но которая не удалась, но на самом деле оно связано с обещанием, возвращенным асинхронной функцией-оболочкой, внутри которой вы выдаете ошибку. Асинхронные функции неявно возвращают обещания.

В этом случае вам доступны следующие варианты:

  • добавление .catch() к вызову функции оболочки (тогда вам даже не понадобится блок try / catch внутри оболочки)
(async function () {
  try {
      await returnsPromise()
  } catch (error) {
      console.log('That did not go well.')
      throw error
  }
})().catch( e => { console.error(e) })
  • использование process.exit(1) вместо throw для завершения скрипта (лениво, но эффективно…)
(async function () {
try {
       await returnsPromise()
   } catch (error) {
       console.error(error)
       process.exit(1)
   }
console.log('This will not be printed.');
})()

Может быть чище?

Если все, что вам нужно, - это завершить сценарий и отобразить ошибку, вы можете просто полностью избавиться от блока try/catch. Уловка в конце IIFE позаботится об отклоненном обещании от returnsPromise.

Опять же, это довольно ленивое решение, которое может иметь неприятные последствия в более сложном сценарии.

(async function () {
  await returnsPromise()
  console.log('This will not be printed.');
})().catch( e => { console.error(e) })

Вам всегда нужно добавлять .catch () в конец IIFE?

Нет, если вы поймаете и обработаете все внутри функции.

Если вы хотите завершить сценарий, вы можете поймать ошибку и выйти из процесса с помощью process.exit (1) вместо использования throw, как это с .catch():

(async function () {
await returnsPromise().catch((e) => { console.error(e); process.exit(1) })
console.log('This will not be printed.');
})()

или как это с try/catch:

(async function () {
   try {
       await returnsPromise()
   } catch (error) {
       console.error(error)
       process.exit(1)
   }
   console.log('This will not be printed.');
})()

Но это становится немного повторяющимся, если в вашем скрипте есть несколько await.

Наконец, для ясности: если вы хотите, чтобы сценарий продолжался, вполне подойдет .catch () или try / catch без броска. Вы можете условно выполнить более поздние части кода. Например, result ниже будет undefined:

(async function () {
var result = await returnsPromise().catch((e) => { console.error(e.message) })
console.log( result ? 'This was a success! ' + result : 'This was a failure.' )
})()