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, thrownã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..catchmotivo , 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..catchnã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 catchconstruçõ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 Promiseou Promise.resolveinicia seu trycódigo. Ligar throwou Promise.rejectenviar você para o catchcó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..catchpode ser aninhado. Seu authenticate()método pode ter internamente um try..catchbloco 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 throwuma exceção, se fosse um código síncrono.
Se seu fluxo de controle for mais simples, com algumas ifverificações em suas thendeclaraçõ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.
rejecte 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.