Когда есть. То (успех, неудача) считается антипаттерном для promises?
Я рассмотрел рекомендацию по обещанию bluebird, в которой упоминается, что .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) })
Какая разница?
Ответы
Ответ 1
Какая разница?
Вызов .then()
возвращает обещание, которое будет отклонено, если обратный вызов вызывает ошибку. Это означает, что если ваш успех logger
не удался, ошибка будет передана в следующий обратный вызов .catch()
, но не к обратному сообщению fail
, который идет вместе с success
.
Здесь диаграмма управляющего потока:
![control flow diagram of then with two arguments]()
![control flow diagram of then catch chain]()
Чтобы выразить это в синхронном коде:
// 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
также будет обрабатывать исключения из вызова журнала ошибок.
Так много для разницы.
Я не совсем понимаю его объяснение, как для try and catch
Аргумент состоит в том, что обычно вы хотите поймать ошибки на каждом шаге обработки и не использовать их в цепочках. Ожидается, что у вас будет только один конечный обработчик, который обрабатывает все ошибки. В то время как при использовании "antipattern" ошибки в некоторых из обратных вызовов не обрабатываются.
Однако этот шаблон действительно очень полезен: когда вы хотите обрабатывать ошибки, которые произошли именно на этом шаге, и вы хотите сделать что-то совершенно другое, если ошибка не произошла - то есть когда ошибка невосстановима. Помните, что это ветвление вашего потока управления. Конечно, это иногда желательно.
Что не так с этим?
some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
Чтобы повторить обратный вызов. Вы скорее хотите
some_promise_call()
.catch(function(e) {
return e; // it OK, we'll just log it
})
.done(function(res) {
logger.log(res);
});
Вы также можете использовать .finally()
для этого.
Ответ 2
Оба не совсем идентичны. Разница в том, что в первом примере не будет обнаружено исключение, которое было бы выбрано в вашем обработчике success
. Поэтому, если ваш метод должен только возвращать разрешенный promises, как это часто бывает, вам нужен трейлингер catch
(или еще один then
с пустым success
параметром). Конечно, может быть, ваш обработчик then
не сделает ничего, что потенциально может потерпеть неудачу, и в этом случае использование одного 2-параметра then
может быть прекрасным.
Но я считаю, что точка текста, с которой вы связаны, заключается в том, что then
в основном полезен против обратных вызовов в его способности связывать множество асинхронных шагов, а когда вы на самом деле делаете это, 2-параметрическая форма then
тонко не ведет себя так, как ожидалось, по вышеуказанной причине. Это особенно противоречиво при использовании средней цепи.
Как кто-то, кто сделал много сложного асинхронного материала и натолкнулся на такие углы больше, чем я хотел бы признать, я действительно рекомендую избегать этого анти-шаблона и идти с помощью отдельного подхода к обработчикам.
Ответ 3
Изучая преимущества и недостатки обоих, мы можем сделать расчетное предположение о том, что подходит для ситуации.
Это два основных подхода к реализации promises. У обоих есть плюсы и минус
Catch Approach
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
<сильные > Преимущества
- Все ошибки обрабатываются одним блоком catch.
- Даже улавливает любое исключение в блоке then.
- Цепочка множественных обратных вызовов успеха
Недостатки
- В случае цепочки становится трудно отображать разные сообщения об ошибках.
Подход к успеху/ошибкам
some_promise_call()
.then(function success(res) { logger.log(res) },
function error(err) { logger.log(err) })
<сильные > Преимущества
- Вы получаете мелкозернистый контроль ошибок.
- У вас может быть обычная функция обработки ошибок для различных категорий ошибок, таких как ошибка db, ошибка 500 и т.д.
Disavantages
- Вам все равно потребуется еще один
catch
, если вы хотите обработать ошибки, вызванные обратным вызовом успеха
Ответ 4
Простое объяснение:
В ES2018
Когда метод catch вызывается с аргументом onRejected, предпринимаются следующие шаги:
- Пусть обещание будет этим значением.
- Вернуть? Invoke (обещание, "затем", "неопределено, onRejected").
это означает:
promise.then(f1).catch(f2)
равняется
promise.then(f1).then(undefiend, f2)
Ответ 5
Использование .then().catch()
позволяет вам включить Promise Chaining, которая требуется для выполнения рабочего процесса. Возможно, вам понадобится прочитать некоторую информацию из базы данных, затем вы захотите передать ее асинхронному API, а затем захотите манипулировать ответом. Вы можете отправить ответ обратно в базу данных. Обработка всех этих рабочих процессов с вашей концепцией выполнима, но очень сложна в управлении. Лучшим решением будет then().then().then().then().catch()
который получает все ошибки всего за один раз и позволяет вам сохранить работоспособность кода.
Ответ 6
Вместо слов, хороший пример. Следующий код (если первое обещание разрешено):
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'); }
)