Допустим, у меня есть функция аутентификации, которая возвращает обещание. Обещание затем разрешается с результатом. Ложь и истина - это ожидаемые результаты, на мой взгляд, и отклонения должны происходить только в случае ошибки. Или, считается ли сбой в аутентификации чем-то, от чего вы бы отказались?
javascript
Матье Бертин
источник
источник
reject
и не возвращать false, но если вы ожидаете, что значение будет aBool
, то вы добились успеха, и вы должны решить с Bool независимо от значения. Обещания являются своего рода прокси для значений - они хранят возвращаемое значение, поэтому только если вы не можете получить это значениеreject
. В противном случае вы должныresolve
.false
или как исключение?then
когда сервер отвечает - даже если возвращается код ошибки - и вы должны проверитьresponse.ok
.catch
Обработчик срабатывает только для неожиданных ошибок.Ответы:
Хороший вопрос! Трудного ответа нет. Это зависит от того, что вы считаете исключительным в этой конкретной точке потока .
Отклонение -
Promise
это то же самое поднятие исключения. Не все нежелательные результаты являются исключительными , результат ошибок . Вы можете утверждать ваше дело в обоих направлениях:Ошибка аутентификации должен
reject
Promise
, потому что абонент ожидаетUser
объект в ответ, и все остальное является исключением из этого потока.Ошибка аутентификация должна , хотя и , поскольку предоставление неправильных учетных данных не действительно исключительное
resolve
Promise
null
случай, и вызывающий абонент не должен ожидать , что поток всегда приводит вUser
.Обратите внимание, что я смотрю на проблему со стороны звонящего . В потоке информации, ожидает ли звонящий его действия приведут к
User
(и что-либо еще является ошибкой), или имеет ли смысл для этого конкретного вызывающего обрабатывать другие результаты?В многослойной системе ответ может меняться по мере прохождения данных через слои. Например:
null
пользователю.Этот пример с 4 пунктами, очевидно, сложен, но он иллюстрирует 2 пункта:
Итак, еще раз, нет жесткого ответа. Время подумать и спроектировать!
источник
Таким образом, у Promises есть замечательное свойство, заключающееся в том, что они приносят JS из функциональных языков, а именно то, что они действительно реализуют этот
Either
конструктор типов, который склеивает вместе два других типа,Left
тип иRight
тип, заставляя логику брать одну ветвь или другую. ветка.Теперь вы действительно замечаете, что тип на левой стороне неоднозначен для обещаний; Вы можете отказаться с чем угодно. Это верно, потому что JS слабо типизирован, но вы должны быть осторожны, если вы программируете в обороне.
Причина в том, что JS будет принимать
throw
операторы из кода обработки обещаний и связывать его вLeft
сторону этого. Технически в JS вы можете делатьthrow
все, в том числе true / false, или строку, или число: но код JavaScript также выбрасывает вещи безthrow
(когда вы делаете такие вещи, как попытка получить доступ к свойствам на пустых значениях), и для этого (Error
объекта) существует установленный API , Поэтому, когда вы приступаете к ловле, обычно приятно предположить, что эти ошибки являютсяError
объектами. А посколькуreject
обещание будет агломерировать при возникновении любых ошибок из любых вышеперечисленных ошибок, вы, как правило, хотите делать толькоthrow
другие ошибки, чтобыcatch
утверждение имело простую согласованную логику.Поэтому, хотя вы можете поставить условное
catch
выражение в вашем и искать ложные ошибки, в этом случае истинный случай тривиален,вы, вероятно, предпочтете логическую структуру, по крайней мере, для того, что приходит сразу выходит из аутентификатора, из более простого булева:
Фактически, следующий уровень логики аутентификации - это, вероятно, возвращение какого-то
User
объект, содержащий аутентифицированного пользователя, так что это становится:и это более или менее то, что я ожидал: вернуть
null
в случае, если пользователь не определен, иначе вернуть{user_id: <number>, permission_to_launch_missiles: <boolean>}
. Я ожидаю, что общий случай не входа в систему является спасительным, например, если мы находимся в каком-то режиме «демо для новых клиентов», и его не следует смешивать с ошибками, когда я случайно вызвалobject.doStuff()
когдаobject.doStuff
былundefined
.Теперь, с учетом сказанного, вы можете захотеть определить исключение
NotLoggedIn
илиPermissionError
исключение из негоError
. Тогда в вещах, которые действительно нуждаются в этом, вы хотите написать:источник
ошибки
Давайте поговорим об ошибках.
Есть два типа ошибок:
Ожидаемые ошибки
Ожидаемые ошибки - это состояния, в которых происходит неправильная вещь, но вы знаете, что это может произойти, поэтому вы справляетесь с этим.
Это такие вещи, как пользовательский ввод или запросы к серверу. Вы знаете, что пользователь может ошибиться или сервер не работает, поэтому вы пишете некоторый проверочный код, чтобы убедиться, что программа снова запрашивает ввод, или отображает сообщение, или какое-либо другое подходящее поведение.
Они восстанавливаются при обработке. Если оставить их без внимания, они станут неожиданными ошибками.
Неожиданные ошибки
Неожиданные ошибки (ошибки) - это состояния, в которых происходит что-то неправильное, потому что код неправильный. Вы знаете, что они в конечном итоге произойдут, но нет способа узнать, где или как с ними бороться, потому что по определению они неожиданны.
Это такие вещи, как синтаксические и логические ошибки. Возможно, в вашем коде есть опечатка, возможно, вы вызвали функцию с неправильными параметрами. Они, как правило, не подлежат восстановлению.
try..catch
Давайте поговорим о
try..catch
.В JavaScript
throw
обычно не используется. Если вы посмотрите на примеры в коде, их будет немного и далеко друг от друга, и они обычно структурированы по типуИз-за этого,
try..catch
блоки не так уж и распространены для потока управления. Обычно довольно легко добавить некоторые проверки перед вызовом методов, чтобы избежать ожидаемых ошибок.Среды JavaScript тоже довольно прощающие, поэтому неожиданные ошибки также часто остаются невредимыми.
C # :try..catch
не должно быть необычным. Есть несколько хороших вариантов использования, которые более распространены в таких языках, как Java и C #. Java и C # имеют преимущество типизированногоcatch
конструкций, так что вы можете различать ожидаемые и неожиданные ошибки:Этот пример позволяет другим неожиданным исключениям возникать и обрабатываться в другом месте (например, путем регистрации и закрытия программы).
В JavaScript эта конструкция может быть воспроизведена с помощью:
Не так элегантно, что является одной из причин, почему это необычно.
функции
Давайте поговорим о функциях.
Если вы используете принцип единой ответственности , каждый класс и функция должны служить единственной цели.
Например,
authenticate()
может аутентифицировать пользователя.Это может быть записано как:
В качестве альтернативы это может быть записано как:
Оба приемлемы.
обещания
Давайте поговорим об обещаниях.
Обещания являются асинхронной формой
try..catch
. Звонокnew Promise
илиPromise.resolve
начинает вашtry
код. Звонитthrow
илиPromise.reject
отправляет вамcatch
код.Если у вас есть асинхронная функция для аутентификации пользователя, вы можете написать ее так:
В качестве альтернативы это может быть записано как:
Оба приемлемы.
гнездование
Давайте поговорим о вложенности.
try..catch
может быть вложенным. Вашauthenticate()
метод может иметь внутреннийtry..catch
блок, такой как:Аналогично обещания могут быть вложенными. Ваш асинхронный
authenticate()
метод может внутренне использовать обещания:Так каков ответ?
Ладно, думаю, пришло время ответить на вопрос:
Самый простой ответ, который я могу дать, состоит в том, что вы должны отказаться от обещания, где бы вы ни хотели
throw
сделать исключение, если бы это был синхронный код.Если ваш поток управления проще благодаря нескольким
if
проверкам в вашихthen
утверждениях, нет необходимости отклонять обещание.Если ваш поток управления проще, отклонив обещание, а затем проверив типы ошибок в коде обработки ошибок, сделайте это вместо этого.
источник
Я использовал ветку «отклонить» в Promise для представления действия «отмена» диалоговых окон пользовательского интерфейса jQuery. Это казалось более естественным, чем использование ветви «resol», не в последнюю очередь потому, что в диалоговом окне часто есть несколько вариантов «close».
источник
Выполнение обещания более или менее похоже на условие «если». Вам решать, хотите ли вы «разрешить» или «отклонить», если аутентификация не удалась.
источник
try..catch
, нетif
.try...catch
и просто сказать, что если вы смогли выполнить и получить результат, вы должны разрешить независимо от полученного значения, в противном случае вы должны отклонить?try { if (!doSomething()) throw whatever; doSomethingElse() } catch { ... }
прекрасно, но конструкция, которуюPromise
представляет собой, являетсяtry..catch
частью, а неif
частью.doSomething()
не получится, то он выдаст, но если нет, он может содержать значение, которое вам нужно (вашеif
приведенное выше немного сбивает с толку, поскольку это не является частью вашей идеи здесь :)). Вы должны только отклонить, если есть причина бросить (в аналогии), так, если тест не удался. Если тест прошел успешно, вы всегда должны решить, независимо от того, является ли его значение положительным, верно?