Скажем, у меня есть коды, как показано ниже:

process.on('unhandledRejection', (reason, promise) => {
  console.log(reason, promise)
})

Promise.reject()

Promise.reject вызывается без каких-либо параметров, а обработчик unhandledRejection выводит что-то вроде undefined Promise { <rejected> undefined }. Не было никакой информации, чтобы найти настоящее обещание. Итак, как я могу получить контекст об отклоненном обещании в этом случае?

Заранее спасибо.

0
L_K 15 Апр 2020 в 09:23

1 ответ

Лучший ответ

На самом деле не имеет значения, есть ли в обещании ошибка или нет.

Отклоненные обещания обычно отличаются от исключений . Они асинхронны. А они просто объекты.

Синхронная обработка ошибок

Вы можете определить, где возникло исключение:

if(true){
  throw undefined //Definitely here
}

Однако все становится сложнее, если у вас есть функции:

function throwUndefined(){
  throw undefined //Here?
}

function maybeThrow(throwException){
  if(throwException){
    throwUndefined() //Or here?
  }
}

maybeThrow(true) //Or here?

Собственно, и то и другое три места. Вот тут и появляется стек ошибки.

Он представляет стек вызовов в момент возникновения исключения. В приведенном выше примере это будет примерно так:

throwUndefined (line 2) 
maybeThrow (line 7)
main (line 11)

Но обещания разные

Этот стек может быть действительно полезен для синхронного кода, но ... асинхронность выходит за рамки стека!

Когда основной скрипт завершается и появляется из стека, код не останавливается: асинхронность начинается именно там.

Один шаг за пределы стека

Цикл событий включается и начинает обрабатывать «волшебные» вещи, такие как обещания и таймауты.

А теперь, где обещание в конце кода?

const a = new Promise((resolve) => { //Here?
  setTimeout(() => {
    resolve()
    b = a //Or here?
  }, 100)
})
a.then(() => { //Here?
  console.log(b) //Here?
})
let b //Or maybe here?

Оба эти места!

Однако это не может быть представлено линейной структурой (например, стеком), поскольку некоторые части меняются со временем.

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

const a = Promise.reject() //If the code would terminate here, you couldn't add the catch listener
a.catch(console.error)

Таким образом, предупреждение выдается только после , когда стек вызвал отклонение обещания, и с тех пор могли произойти другие изменения.

Обратите внимание на следующее:

let a = Promise.reject()
a = undefined

//Warning: `a` was rejected! But was it? Well, no... `a` is just `undefined`

Или более реалистичный пример:

const array = [Promise.resolve(), Promise.resolve(), Promise.reject(), Promise.resolve(), Promise.resolve(), Promise.resolve(), Promise.resolve(), Promise.resolve()]
for(const promise of array){
  const x = promise.then() //Forward data to `x`
}

//Warning: `x` was rejected! Exactly which  `x` of the 8? 

Ничего страшного, но ответьте, пожалуйста, на мой вопрос!

Как найти обещание?

Все просто: у вас есть ссылка! Что еще тебе нужно?

Если вы сравните ссылку в аргументе promise используемых вами обещаний, вы сможете найти, какое из них было отклонено, и оттуда несложно выяснить, где это произошло.

И совет в конце: обрабатывайте все обещания (или цепочки обещаний), даже те, от которых вы не ожидаете отказаться.

0
Community 20 Июн 2020 в 09:12