Когда.then(успех, провал) считается антипаттерном для обещаний?
Я взглянул на FAQ об обещании синей птицы, в котором упоминается, что .then(success, fail)
это антипаттерн. Я не совсем понимаю его объяснение, что касается попытки поймать. Что не так с этим следующим?
some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
Кажется, что пример предлагает следующее как правильный путь.
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
Какая разница?
5 ответов
Какая разница?
.then()
call возвратит обещание, которое будет отклонено в случае, если обратный вызов выдаст ошибку. Это значит, когда твой успех logger
терпит неудачу, ошибка будет передана следующему .catch()
обратный вызов, но не на fail
обратный вызов, который идет вместе с success
,
Вот схема потока управления:
Чтобы выразить это в синхронном коде:
// some_promise_call().then(logger.log, logger.log)
then: {
try {
var results = some_call();
} catch(e) {
logger.log(e);
break then;
} // else
logger.log(results);
}
Второй log
(что походит на первый аргумент .then()
) будет выполняться только в том случае, если исключение не произошло. Помеченный блок и break
заявление кажется немного странным, это на самом деле то, что есть в Python try-except-else
для(рекомендуется чтение!).
// some_promise_call().then(logger.log).catch(logger.log)
try {
var results = some_call();
logger.log(results);
} catch(e) {
logger.log(e);
}
catch
logger также будет обрабатывать исключения из успешного вызова журнала.
Так много для разницы.
Я не совсем понимаю его объяснение относительно попытки поймать
Аргумент заключается в том, что обычно вы хотите отлавливать ошибки на каждом этапе обработки и не должны использовать его в цепочках. Предполагается, что у вас есть только один конечный обработчик, который обрабатывает все ошибки, в то время как при использовании "antipattern" ошибки в некоторых из обратных вызовов не обрабатываются.
Однако этот шаблон на самом деле очень полезен: когда вы хотите обработать ошибки, которые произошли именно на этом шаге, и вы хотите сделать что-то совершенно иное, когда ошибка не произошла - то есть, когда ошибка не устраняется. Помните, что этоветвит ваш поток управления. Конечно, это иногда желательно.
Что не так с этим следующим?
some_promise_call() .then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
Что вам пришлось повторить ваш обратный звонок. Ты скорее хочешь
some_promise_call()
.catch(function(e) {
return e; // it's OK, we'll just log it
})
.done(function(res) {
logger.log(res);
});
Вы также можете рассмотреть возможность использования.finally()
за это.
Два не совсем идентичны. Разница в том, что первый пример не поймает исключение, которое выдается в вашем success
обработчик. Так что, если ваш метод должен только когда-либо возвращать разрешенные обещания, как это часто бывает, вам нужен трейлинг catch
обработчик (или еще один then
с пустым success
параметр). Конечно, может быть, что ваш then
обработчик не делает ничего, что потенциально может дать сбой, и в этом случае используется один 2-параметр then
может быть в порядке.
Но я считаю, что смысл текста, на который вы ссылаетесь, заключается в том, что then
в основном полезен по сравнению с обратными вызовами в своей способности связывать несколько асинхронных шагов, и когда вы действительно делаете это, 2-параметрическая форма then
тонко ведет себя не совсем так, как ожидалось, по вышеуказанной причине. Это особенно нелогично, когда используется средняя цепь.
Как человек, который сделал много сложных асинхронных вещей и столкнулся с такими углами больше, чем я хотел бы признать, я действительно рекомендую избегать этого анти-паттерна и придерживаться подхода отдельного обработчика.
Рассматривая преимущества и недостатки обоих, мы можем сделать расчетное предположение относительно того, что подходит для данной ситуации. Это два основных подхода к выполнению обещаний. У обоих есть свои плюсы и минусы
Поймать подход
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
преимущества
- Все ошибки обрабатываются одним блоком перехвата.
- Даже ловит любое исключение в тогдашнем блоке.
- Цепочка нескольких успешных обратных вызовов
Недостатки
- В случае создания цепочки становится трудно отображать разные сообщения об ошибках.
Подход Успех / Ошибка
some_promise_call()
.then(function success(res) { logger.log(res) },
function error(err) { logger.log(err) })
преимущества
- Вы получаете детальный контроль ошибок.
- Вы можете иметь общую функцию обработки ошибок для различных категорий ошибок, таких как ошибка db, ошибка 500 и т. Д.
Disavantages
- Вам все еще понадобится другой
catch
если вы хотите обработать ошибки, вызванные обратным вызовом успеха
Простое объяснение:
В ES2018
Когда метод catch вызывается с аргументом onRejected, предпринимаются следующие шаги:
- Пусть обещание будет этим значением.
- Вернуть? Invoke(обещание, "затем", "неопределено, onRejected").
это означает:
promise.then(f1).catch(f2)
равняется
promise.then(f1).then(undefiend, f2)
С помощью .then().catch()
позволяет вам включить Promise Chaining, которая необходима для выполнения рабочего процесса. Возможно, вам понадобится прочитать некоторую информацию из базы данных, затем вы захотите передать ее асинхронному API, а затем захотите манипулировать ответом. Вы можете отправить ответ обратно в базу данных. Обработка всех этих рабочих процессов с вашей концепцией выполнима, но очень сложна в управлении. Лучшее решение будет then().then().then().then().catch()
который получает все ошибки всего за один раз и позволяет вам сохранить удобство сопровождения кода.
С помощью then()
а также catch()
помогает связать успех и обработчик неудач в обещании.catch()
работает по обещанию, возвращенному then()
. Он обрабатывает,
- Если обещание было отклонено. Смотрите #3 на картинке
- Если ошибка произошла в обработчике успеха then(), между номерами строк с 4 по 7 ниже. См. № 2.a на картинке (обратный вызов при сбое на
then()
не справляется с этим.) - Если ошибка произошла в обработчике ошибок then(), строка номер 8 ниже. См. № 3.b на рисунке.
1. let promiseRef: Promise = this. aTimetakingTask (false);
2. promiseRef
3. .then(
4. (result) => {
5. /* successfully, resolved promise.
6. Work on data here */
7. },
8. (error) => console.log(error)
9. )
10. .catch( (e) => {
11. /* successfully, resolved promise.
12. Work on data here */
13. });
Примечание. Часто обработчик сбоев может не определяться, если
catch()
уже написано. РЕДАКТИРОВАТЬ:reject()
привести к вызовуcatch()
только если обработчик ошибок вthen()
это не определено. Уведомление №3 на картинке кcatch()
. Он вызывается, когда обработчик в строках №8 и 9 не определен.
Это имеет смысл, потому что обещание, возвращаемое then()
не имеет ошибки, если обратный вызов позаботится об этом.
Вместо слов хороший пример. Следующий код (если первое обещание разрешено):
Promise.resolve()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
идентичен:
Promise.resolve()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)
Но с отклоненным первым обещанием это не идентично:
Promise.reject()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
Promise.reject()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)