ошибки
Давайте поговорим об ошибках.
Есть два типа ошибок:
- ожидаемые ошибки
- неожиданные ошибки
- отдельные ошибки
Ожидаемые ошибки
Ожидаемые ошибки - это состояния, в которых происходит неправильная вещь, но вы знаете, что это может произойти, поэтому вы справляетесь с этим.
Это такие вещи, как пользовательский ввод или запросы к серверу. Вы знаете, что пользователь может ошибиться или сервер не работает, поэтому вы пишете некоторый проверочный код, чтобы убедиться, что программа снова запрашивает ввод, или отображает сообщение, или какое-либо другое подходящее поведение.
Они восстанавливаются при обработке. Если оставить их без внимания, они станут неожиданными ошибками.
Неожиданные ошибки
Неожиданные ошибки (ошибки) - это состояния, в которых происходит что-то неправильное, потому что код неправильный. Вы знаете, что они в конечном итоге произойдут, но нет способа узнать, где или как с ними бороться, потому что по определению они неожиданны.
Это такие вещи, как синтаксические и логические ошибки. Возможно, в вашем коде есть опечатка, возможно, вы вызвали функцию с неправильными параметрами. Они, как правило, не подлежат восстановлению.
try..catch
Давайте поговорим о try..catch
.
В JavaScript throw
обычно не используется. Если вы посмотрите на примеры в коде, их будет немного и далеко друг от друга, и они обычно структурированы по типу
function example(param) {
if (!Array.isArray(param) {
throw new TypeError('"param" should be an array!');
}
...
}
Из-за этого, try..catch
блоки не так уж и распространены для потока управления. Обычно довольно легко добавить некоторые проверки перед вызовом методов, чтобы избежать ожидаемых ошибок.
Среды JavaScript тоже довольно прощающие, поэтому неожиданные ошибки также часто остаются невредимыми.
try..catch
не должно быть необычным. Есть несколько хороших вариантов использования, которые более распространены в таких языках, как Java и C #. Java и C # имеют преимущество типизированногоcatch
конструкций, так что вы можете различать ожидаемые и неожиданные ошибки:
C # :
try
{
var example = DoSomething();
}
catch (ExpectedException e)
{
DoSomethingElse(e);
}
Этот пример позволяет другим неожиданным исключениям возникать и обрабатываться в другом месте (например, путем регистрации и закрытия программы).
В JavaScript эта конструкция может быть воспроизведена с помощью:
try {
let example = doSomething();
} catch (e) {
if (e instanceOf ExpectedError) {
DoSomethingElse(e);
} else {
throw e;
}
}
Не так элегантно, что является одной из причин, почему это необычно.
функции
Давайте поговорим о функциях.
Если вы используете принцип единой ответственности , каждый класс и функция должны служить единственной цели.
Например, authenticate()
может аутентифицировать пользователя.
Это может быть записано как:
const user = authenticate();
if (user == null) {
// keep doing stuff
} else {
// handle expected error
}
В качестве альтернативы это может быть записано как:
try {
const user = authenticate();
// keep doing stuff
} catch (e) {
if (e instanceOf AuthenticationError) {
// handle expected error
} else {
throw e;
}
}
Оба приемлемы.
обещания
Давайте поговорим об обещаниях.
Обещания являются асинхронной формой try..catch
. Звонок new Promise
или Promise.resolve
начинает ваш try
код. Звонит throw
или Promise.reject
отправляет вам catch
код.
Promise.resolve(value) // try
.then(doSomething) // try
.then(doSomethingElse) // try
.catch(handleError) // catch
Если у вас есть асинхронная функция для аутентификации пользователя, вы можете написать ее так:
authenticate()
.then((user) => {
if (user == null) {
// keep doing stuff
} else {
// handle expected error
}
});
В качестве альтернативы это может быть записано как:
authenticate()
.then((user) => {
// keep doing stuff
})
.catch((e) => {
if (e instanceOf AuthenticationError) {
// handle expected error
} else {
throw e;
}
});
Оба приемлемы.
гнездование
Давайте поговорим о вложенности.
try..catch
может быть вложенным. Ваш authenticate()
метод может иметь внутренний try..catch
блок, такой как:
try {
const credentials = requestCredentialsFromUser();
const user = getUserFromServer(credentials);
} catch (e) {
if (e instanceOf CredentialsError) {
// handle failure to request credentials
} else if (e instanceOf ServerError) {
// handle failure to get data from server
} else {
throw e; // no idea what happened
}
}
Аналогично обещания могут быть вложенными. Ваш асинхронный authenticate()
метод может внутренне использовать обещания:
requestCredentialsFromUser()
.then(getUserFromServer)
.catch((e) => {
if (e instanceOf CredentialsError) {
// handle failure to request credentials
} else if (e instanceOf ServerError) {
// handle failure to get data from server
} else {
throw e; // no idea what happened
}
});
Так каков ответ?
Ладно, думаю, пришло время ответить на вопрос:
Считается ли сбой в аутентификации чем-то, за что вы бы отказались?
Самый простой ответ, который я могу дать, состоит в том, что вы должны отказаться от обещания, где бы вы ни хотели throw
сделать исключение, если бы это был синхронный код.
Если ваш поток управления проще благодаря нескольким if
проверкам в ваших then
утверждениях, нет необходимости отклонять обещание.
Если ваш поток управления проще, отклонив обещание, а затем проверив типы ошибок в коде обработки ошибок, сделайте это вместо этого.
reject
и не возвращать false, но если вы ожидаете, что значение будет aBool
, то вы добились успеха, и вы должны решить с Bool независимо от значения. Обещания являются своего рода прокси для значений - они хранят возвращаемое значение, поэтому только если вы не можете получить это значениеreject
. В противном случае вы должныresolve
.