Я все еще новичок в promises и использую bluebird в настоящее время, однако у меня есть сценарий, в котором я не совсем уверен, как с этим лучше всего справиться.
Так, например, у меня есть цепочка обещаний в экспресс-приложении, например:
repository.Query(getAccountByIdQuery)
.catch(function(error){
res.status(404).send({ error: "No account found with this Id" });
})
.then(convertDocumentToModel)
.then(verifyOldPassword)
.catch(function(error) {
res.status(406).send({ OldPassword: error });
})
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
Итак, поведение, которое мне нужно, это:
- Идет получить аккаунт по Id
- Если на этом этапе есть отказ, выйдите из строя и верните ошибку
- Если ошибки нет, преобразовать документ, возвращенный в модель
- Подтвердите пароль с документом базы данных
- Если пароли не совпадают, взорвитесь и верните другую ошибку
- Если ошибок нет, измените пароли
- Затем верните успех
- Если что-то еще пошло не так, верните 500
Итак, в настоящее время уловы, похоже, не останавливают цепочку, и это имеет смысл, поэтому мне интересно, есть ли у меня способ каким-то образом заставить цепочку останавливаться в определенной точке на основе ошибок, или есть лучший способ чтобы структурировать это, чтобы получить некоторую форму поведения ветвления, как в случае if X do Y else Z
.
Любая помощь была бы замечательной.
javascript
node.js
promise
bluebird
Grofit
источник
источник
Ответы:
Это поведение в точности похоже на синхронный бросок:
Это половина цели
.catch
- уметь восстанавливаться после ошибок. Может быть желательно выполнить повторный запуск, чтобы сигнализировать, что состояние все еще является ошибкой:Однако это само по себе не сработает в вашем случае, поскольку ошибка будет обнаружена более поздним обработчиком. Настоящая проблема здесь в том, что обобщенные обработчики ошибок типа «HANDLE ANYTHING» - плохая практика в целом и крайне не одобряются другими языками программирования и экосистемами. По этой причине Bluebird предлагает типизированные и предикатные уловки.
Дополнительным преимуществом является то, что ваша бизнес-логика вообще не должна (и не должна) знать о цикле запроса / ответа. Ответственность за запрос не состоит в том, чтобы решить, какой HTTP-статус и ошибка получает клиент, а позже, по мере роста вашего приложения, вы можете захотеть отделить бизнес-логику (как запрашивать вашу БД и как обрабатывать ваши данные) от того, что вы отправляете клиенту. (какой код статуса http, какой текст и какой ответ).
Вот как я бы написал ваш код.
Во-первых, мне нужно
.Query
было создатьNoSuchAccountError
подкласс, изPromise.OperationalError
которого Bluebird уже предоставляет. Если вы не знаете, как создать подкласс ошибки, дайте мне знать.Я бы дополнительно разделил его на подклассы,
AuthenticationError
а затем сделал бы что-то вроде:Как видите - он очень чистый, и вы можете прочитать текст как инструкцию о том, что происходит в процессе. Он также отделен от запроса / ответа.
Теперь я бы вызвал его из обработчика маршрута как таковой:
Таким образом, вся логика находится в одном месте, и решение о том, как обрабатывать ошибки для клиента, находится в одном месте, и они не загромождают друг друга.
источник
.catch(someSpecificError)
обработчика для какой-то конкретной ошибки заключается в том, что вы хотите перехватить определенный тип ошибки (которая безвредна), обработать ее и продолжить следующий поток. Например, у меня есть код запуска, в котором есть последовательность действий. Первым делом нужно прочитать файл конфигурации с диска, но если этот файл конфигурации отсутствует, это ошибка ОК (программа имеет стандартные значения по умолчанию), поэтому я могу обработать эту конкретную ошибку и продолжить остальную часть потока. Также может быть уборка, которую лучше не оставлять на потом.instanceof
ловушке всего и самостоятельно выполняете chceks..catch
работает какtry-catch
оператор, а это значит, что вам нужен только один улов в конце:источник
Нет. Вы не можете "закончить" цепочку, если не вызовете исключение, которое пузырится до конца. См . Ответ Бенджамина Грюнбаума, чтобы узнать, как это сделать.
Вывод из его рисунка будет не различать типы ошибок, но использовать ошибки , которые имеют
statusCode
иbody
поле , которые могут быть отправлены из одного, универсального.catch
обработчика. Однако в зависимости от структуры вашего приложения его решение может быть чище.Да, вы можете выполнять ветвление с помощью обещаний . Однако это означает покинуть цепочку и «вернуться» к вложению - точно так же, как вы это сделали бы во вложенных операторах if-else или try-catch:
источник
Я делал так:
Вы оставляете свой улов в конце. И просто выдайте ошибку, когда это произойдет на полпути к вашей цепочке.
Другие ваши функции, вероятно, будут выглядеть примерно так:
источник
Возможно, немного опоздал на вечеринку, но можно сделать гнездо,
.catch
как показано здесь:Сеть разработчиков Mozilla - Использование обещаний
Изменить: я отправил это, потому что он в целом обеспечивает запрашиваемую функциональность. Однако в данном конкретном случае это не так. Потому что, как уже подробно объяснялось другими,
.catch
предполагается, что ошибка исправлена. Вы не можете, например, отправить ответ клиенту в нескольких.catch
обратных вызовах, потому что a.catch
без явного разрешенияreturn
разрешает егоundefined
в этом случае, вызывая.then
запуск, даже если ваша цепочка на самом деле не разрешена, что потенциально может привести.catch
к срабатыванию подписки и отправке другой ответ клиенту, вызывающий ошибку и, вероятно, мешающийUnhandledPromiseRejection
вам. Надеюсь, это запутанное предложение имело для вас какой-то смысл.источник
Вместо этого
.then().catch()...
можно сделать.then(resolveFunc, rejectFunc)
. Эта цепочка обещаний была бы лучше, если бы вы обрабатывали вещи попутно. Вот как я бы это переписал:Примечание. Это
if (error != null)
своего рода хитрость для работы с самой последней ошибкой.источник
Я думаю, что приведенный выше ответ Бенджамина Грюнбаума - лучшее решение для сложной логической последовательности, но вот моя альтернатива для более простых ситуаций. Я просто использую
errorEncountered
флаг,return Promise.reject()
чтобы пропустить любые последующие операторыthen
orcatch
. Так это выглядело бы так:Если у вас больше двух пар then / catch, вам, вероятно, следует использовать решение Бенджамина Грюнбаума. Но это работает для простой настройки.
Обратите внимание, что в последнем
catch
есть толькоreturn;
вместоreturn Promise.reject();
, потому что нет последующего,then
который нам нужно пропустить, и он будет считаться необработанным отклонением Promise, что не нравится Node. Как написано выше, финалcatch
вернет мирно разрешенное обещание.источник