Почему обещание отклонить не обрабатывает ошибку

#node.js #promise

Вопрос:

Я использую request пакет nodejs (версия 2.88) с узлом v10.24.1

Приведенное ниже обещание не обрабатывает ошибку, если URL-адрес просто не был указан. Я получаю UnhandledPromiseRejectionWarning и из request package источника я вижу исключение, созданное для этого случая.

Если я удалю async ключевое слово, все будет работать нормально, и отклонение будет обработано.

 return new Promise(async (resolve, reject) =gt; {  request(uri: url).on('error', err =gt; {  reject();  }).on('response', response =gt; {  resolve();  }); });  

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

Комментарии:

1. Функция, которую вы передаете new Promise() , никогда не должна быть асинхронной, но если это так.. Я не понимаю, почему это может провалиться. Поведение должно быть похожим.

2. Поэтому, возможно, вы можете поделиться более полным примером, демонстрирующим, что обработка ошибок не работает. Но просто повторюсь, если это просто академическое упражнение, то круто! Но не используйте здесь асинхронность .

3. @Evert, внешняя функция асинхронна. Все в error порядке, но если URL-адрес не указан, он не работает. Если я просто добавлю try/catch внутри обещания, это тоже будет работать нормально, но я понимаю, что это неправильно и не должно быть так.

4. Ах, это имеет смысл! Я отвечу на этот вопрос.

Ответ №1:

Когда вы передаете функцию new Promise , эта функция немедленно выполняется.

Здесь нет никакой магии, для иллюстрации конструктор new Promise() может выглядеть примерно так:

 class Promise {  constructor(executor) {  executor(this.resolveFunction, this.rejectFunction);   } }  

Итак, этот пример:

 new Promise(() =gt; {  console.log(1); }); console.log(2);  

Выходы:

 1 2  

Это важно, потому что, если вы передадите что-то new Promise , что вызовет исключение, это тоже произойдет немедленно:

 new Promise((res, rej) =gt; {  throw new Error('foo'); });  

Ошибка, возникшая здесь, не приводит к отклонению обещания, она полностью new Promise() предотвращает его выполнение. Обещание не возвращается, и исключение создается во внешней вызванной функции new Promise() .

Однако это нарушается при передаче асинхронной функции:

 new Promise(async (res, rej) =gt; {  throw new Error('foo'); });  

Из-за того, как работают асинхронные функции , эта ошибка не будет вызвана во время настройки new Promise() , но переданная вами асинхронная функция обработает ошибку асинхронно и вернет отклоненное обещание, которое new Promise() не знает, как обрабатывать.

Это ничем не отличается от прямого вызова асинхронной функции самостоятельно и не обработки ошибок:

 (async () =gt; {  throw new Error('foo'); })();  

Таким образом , причина, по которой что-то не получается new Promise() , связана не столько с тем, как работают асинхронные функции в целом, сколько с тем, как они работают.

Просто в последний раз для будущих читателей, вам никогда не следует передавать async исполнителя new Promise() , потому что:

  • Единственная причина, по которой вам async вообще нужно, — это чтобы вы могли использовать await .
  • await работает только с обещаниями.
  • Если у вас уже было обещание , которое вы хотели await , вам не нужно new Promise() было начинать с этого, потому что основной вариант использования- new Promise преобразовать то, что не использует обещания, во что-то, что делает.