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

Использование целой библиотеки, такой как bluebird, исключительно для этой цели, вызывает у меня дискомфорт.

5
Mentor 10 Янв 2017 в 15:54
Что вы имеете в виду под «каждым обещанием, которое вы используете»? Вам нужно только catch ошибок в конце цепочки. Кроме того, что вы подразумеваете под «глотанием»? Если вы хотите предотвратить это, что должно произойти с ошибками?
 – 
Bergi
11 Янв 2017 в 05:14
При использовании большого количества обещаний размещение .catch после каждой цепи может быть утомительным и совсем не СУХИМ. Изменить: с глотанием я имею в виду, что строки с ошибками или подробности не предоставляются. Вместо этого ошибки по умолчанию должны иметь связанный обработчик, в моем случае я хотел, чтобы они отображались в моей консоли узла.
 – 
Mentor
11 Янв 2017 в 16:11
1
Есть другие способы сделать такой код «сухим», кроме как опустить .catch(function(e) {…}), которое везде одинаково. Где началась ваша многочисленная сеть? Обработчики событий, обработчики маршрутов? Затем определите функцию-оболочку, которая устанавливает обработчик и соответствующим образом обрабатывает возвращенные обещания. Если бы вы могли опубликовать свой код, я бы смог написать более конкретный ответ.
 – 
Bergi
11 Янв 2017 в 18:03
1
Написание кода без каких-либо обработчиков .catch() - это просто плохой код. Вы не можете глобально диагностировать отсутствующие обработчики брака. Просто не так писать хороший код. Необязательно ставить .catch() на каждое обещание. У вас должен быть один в каждой цепочке обещаний, поскольку я объясняю логику в своем ответе. Если вы проголосовали против моего ответа, я прошу прощения за то, что дал вам правильный программный ответ на вашу ситуацию. Вы не можете сделать это так, как просите, поэтому я описал, как вам следует поступать с отказами. Если тебе это не нравится, я могу удалить свой ответ.
 – 
jfriend00
11 Янв 2017 в 21:36
1
@ jfriend00, не заметил, что вы там написали. Я не отрицал вас, но не согласен с тем, что это плохой код. Моя цель состояла в том, чтобы просто иметь обработчик ошибок по умолчанию и предотвратить множество идентичных .catches. Если ошибки относятся к программным функциям или пользовательскому опыту, у меня есть .catches для обработки ошибок. Однако в некоторых случаях я просто хочу, чтобы ошибка регистрировалась (либо в консоли, либо в файле журнала, либо в базе данных ошибки). В этом нет ничего плохого :)
 – 
Mentor
28 Авг 2017 в 13:30

2 ответа

Для отслеживания ошибок во время разработки в V8 (последние версии Node.js и Chrome) уже есть unhandledRejection (Node.js) и unhandledrejection (Chrome) прослушиватель событий по умолчанию, что приводит к предупреждению UnhandledPromiseRejectionWarning в Node.js и ошибке Uncaught (in promise) в Chrome.

В предупреждении об устаревании в Node 7 указано, что это будет изменено в будущих версиях Node.js:

Необработанные отклонения обещаний устарели. В будущем необработанные отклонения обещаний завершат процесс Node.js с ненулевым кодом выхода.

Обработка ошибок в обещаниях не является необязательной и должна рассматриваться наравне с try...catch. Каждое обещание, которое может быть отклонено, должно быть связано с catch. А в случае async...await или co .catch идентичен try...catch.

Если предполагается, что ошибка игнорируется, ее нужно перехватить явно. Если обработка ошибок должна быть согласованной во всем приложении и соответствовать уровням журнала, это может быть предусмотрено конструкцией. Например. с обычным пакетом debug:

const debug = require('debug');

function catchFn(err, ns = 'myapp:caughtPromises') {
    debug(ns)(err);
}

function catchPromise(promise, ns) {
    promise.catch(err => catchFn(err, ns));
    return promise;
}

...

try {
  await promise;
} catch (err) {
  catchFn(err);
}

// or
catchPromise(promise);

// or
promise.catch(catchFn);

catchFn также можно расширить для использования сторонней службы ведения журнала.

6
Estus Flask 12 Янв 2017 в 00:17
2
Кажется, это не то, о чем спрашивает OP. Я думаю, что OP имеет .catch() на более высоком уровне, поэтому отказ не остается без внимания. Мне кажется, что они жалуются на то, как трудно определить, где было исходное отклонение, без использования трассировки стека в чем-то вроде Bluebird.
 – 
jfriend00
10 Янв 2017 в 23:54
Тот факт, что OP отправил ответ со слушателем unhandledRejection, говорит сам за себя. Похоже, что у обещаний нет catch на более высоком уровне, потому что в этом случае слушатель неприменим. Если в первую очередь вопрос касается правильной трассировки стека, он был сформулирован неправильно (и в этом случае я бы предложил просто придерживаться BB и не изобретать велосипед, особенно для Node).
 – 
Estus Flask
11 Янв 2017 в 01:38
Я использую node v7, и действительно, обработчика по умолчанию нет. Вот почему я разместил это. Меня беспокоило, что обещания без улова действительно показывают ошибки, но не показывают номера строк и причин. Что касается «Каждое обещание, которое может быть отклонено, должно быть связано с catch»: Да, если действительно нет обработчика по умолчанию. Но в более крупных проектах это означает много ненужного кода.
 – 
Mentor
11 Янв 2017 в 16:12
Если узел не работает с флагом --no-warnings, Promise.reject(); будет выдавать предупреждение UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): undefined как на узле 6, так и на узле 7. Я не уверен, есть ли другие условия, которые могут подавить вывод предупреждений. Опуская catch. это то же самое, что и пропустить `try ... catch. Это также то, что подразумевает сообщение об устаревании - оно вызовет исключение в следующем Node. Конечно, вы можете опустить передовые методы и перехватить все исключения в глобальном масштабе, но предлагать такой подход в ответе просто неправильно.
 – 
Estus Flask
11 Янв 2017 в 19:55

Добавьте в свой процесс обработчика необработанных отказов. Вы можете обработать их один раз таким образом, вместо того, чтобы постоянно копировать и вставлять операторы .catch.

process.on( 'unhandledRejection', ( error, promise ) => {
    console.log( 'UPR: ' + promise + ' with ' + error )
    console.log( error.stack )
} )
1
Mentor 10 Янв 2017 в 15:54
Catch () следует использовать для обработки ошибок, а не только для сообщения о них. После первоначальных усилий по разработке мы обычно хотим знать, когда и где возникла проблема; чем больше контекста, тем лучше, поэтому используйте макросы или именованный обработчик; .catch(fnErr) не требует больших усилий, чтобы напечатать ...
 – 
dandavis
10 Янв 2017 в 16:01
Использование unhandledRejection для обещаний - не лучшая идея, потому что событие unhandledRegjection может сработать где-то еще.
 – 
Vishnu Mishra
10 Янв 2017 в 21:20
Экономить время на обработке ошибок и обрабатывать ошибки глобально - плохая практика. Но unhandledRejection может быть разумным способом отслеживать необработанные отказы, которые не были обнаружены надзором. Но вот в чем проблема. error фактически является отклонением, а не обязательно экземпляром Error. Хотя это хорошая привычка - throw new Error, если отклонение означает ошибку, error может быть любым и пропустить свойство stack. Итак, вот мы - ошибка, которую вовремя не обработал неосторожный разработчик, неожиданно возникает из-за отсутствия стека вызовов (а также вызывает исключение, потому что error не является объектом).
 – 
Estus Flask
11 Янв 2017 в 19:13
@danavis, в этом случае стек дает мне весь необходимый контекст. И действительно, эта техника предназначалась для разработки, а не для живых приложений (это было бы лениво и неудачно).
 – 
Mentor
28 Авг 2017 в 13:32
Этот код предназначен для обнаружения ошибок во время разработки, которые не требуют специальной обработки ошибок. Вы на 100% правы в том, что это полезно только для необработанных отказов, но производственный код никогда не должен попадать в это.
 – 
Mentor
28 Авг 2017 в 13:34