Erros
Vamos falar sobre erros.
Existem dois tipos de erros:
- erros esperados
- erros inesperados
- erros de um por um
Erros esperados
Os erros esperados são estados em que a coisa errada acontece, mas você sabe que pode, então lida com isso.
São coisas como entrada do usuário ou solicitações do servidor. Você sabe que o usuário pode cometer um erro ou que o servidor pode estar inoperante; portanto, escreva algum código de verificação para garantir que o programa solicite a entrada novamente ou exiba uma mensagem ou qualquer outro comportamento apropriado.
Estes são recuperáveis quando manuseados. Se deixados sem tratamento, eles se tornam erros inesperados.
Erros inesperados
Erros inesperados (bugs) são estados em que a coisa errada acontece porque o código está errado. Você sabe que eles acabarão por acontecer, mas não há como saber onde ou como lidar com eles, porque, por definição, são inesperados.
São coisas como erros de sintaxe e de lógica. Você pode ter um erro de digitação no seu código, pode ter chamado uma função com os parâmetros incorretos. Normalmente não são recuperáveis.
try..catch
Vamos conversar try..catch
.
Em JavaScript, throw
não é comumente usado. Se você procurar exemplos em código, eles serão poucos e distantes entre si, e geralmente estruturados de acordo com as linhas de
function example(param) {
if (!Array.isArray(param) {
throw new TypeError('"param" should be an array!');
}
...
}
Por esse try..catch
motivo , os blocos também não são tão comuns no fluxo de controle. Geralmente, é muito fácil adicionar algumas verificações antes de chamar métodos para evitar erros esperados.
Os ambientes JavaScript também são bastante indulgentes; portanto, erros inesperados também costumam ser detectados.
try..catch
não precisa ser incomum. Existem alguns casos de uso interessantes, que são mais comuns em linguagens como Java e C #. Java e C # têm a vantagem de catch
construções digitadas , para que você possa diferenciar entre erros esperados e inesperados:
C # :
try
{
var example = DoSomething();
}
catch (ExpectedException e)
{
DoSomethingElse(e);
}
Este exemplo permite que outras exceções inesperadas fluam e sejam tratadas em outro lugar (como sendo registrado e fechando o programa).
Em JavaScript, essa construção pode ser replicada via:
try {
let example = doSomething();
} catch (e) {
if (e instanceOf ExpectedError) {
DoSomethingElse(e);
} else {
throw e;
}
}
Não é tão elegante, o que é parte da razão pela qual é incomum.
Funções
Vamos falar sobre funções.
Se você usar o princípio da responsabilidade única , cada classe e função deve servir a um propósito singular.
Por exemplo, authenticate()
pode autenticar um usuário.
Isso pode ser escrito como:
const user = authenticate();
if (user == null) {
// keep doing stuff
} else {
// handle expected error
}
Como alternativa, pode ser escrito como:
try {
const user = authenticate();
// keep doing stuff
} catch (e) {
if (e instanceOf AuthenticationError) {
// handle expected error
} else {
throw e;
}
}
Ambos são aceitáveis.
Promessas
Vamos falar de promessas.
Promessas são uma forma assíncrona de try..catch
. Chamando new Promise
ou Promise.resolve
inicia seu try
código. Ligar throw
ou Promise.reject
enviar você para o catch
código.
Promise.resolve(value) // try
.then(doSomething) // try
.then(doSomethingElse) // try
.catch(handleError) // catch
Se você possui uma função assíncrona para autenticar um usuário, pode escrevê-la como:
authenticate()
.then((user) => {
if (user == null) {
// keep doing stuff
} else {
// handle expected error
}
});
Como alternativa, pode ser escrito como:
authenticate()
.then((user) => {
// keep doing stuff
})
.catch((e) => {
if (e instanceOf AuthenticationError) {
// handle expected error
} else {
throw e;
}
});
Ambos são aceitáveis.
Aninhamento
Vamos falar sobre aninhamento.
try..catch
pode ser aninhado. Seu authenticate()
método pode ter internamente um try..catch
bloco como:
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
}
}
Da mesma forma, as promessas podem ser aninhadas. Seu authenticate()
método assíncrono pode usar internamente promessas:
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
}
});
Então qual é a resposta?
Ok, acho que é hora de eu realmente responder à pergunta:
Uma falha na autenticação é considerada algo que você rejeitaria uma promessa?
A resposta mais simples que posso dar é que você deve rejeitar uma promessa em qualquer lugar que desejaria throw
uma exceção, se fosse um código síncrono.
Se seu fluxo de controle for mais simples, com algumas if
verificações em suas then
declarações, não há necessidade de rejeitar uma promessa.
Se o seu fluxo de controle for mais simples, rejeitando uma promessa e, em seguida, verificando tipos de erros no seu código de tratamento de erros, faça-o.
reject
e não deve retornar falso, mas se espera que o valor seja aBool
, teve êxito e deve resolver com o Bool, independentemente do valor. As promessas são uma espécie de proxies para valores - elas armazenam o valor retornado, portanto, somente se o valor não puder ser obtido, você devereject
. Caso contrário, você deveriaresolve
.