Errori
Parliamo di errori.
Esistono due tipi di errori:
- errori previsti
- errori imprevisti
- errori off-by-one
Errori previsti
Gli errori previsti sono stati in cui accade la cosa sbagliata ma sai che potrebbe accadere, quindi devi affrontarla.
Queste sono cose come l'input dell'utente o le richieste del server. Sai che l'utente potrebbe commettere un errore o che il server potrebbe essere inattivo, quindi scrivi un codice di controllo per assicurarti che il programma richieda di nuovo l'input o visualizzi un messaggio o qualunque altro comportamento sia appropriato.
Questi sono recuperabili quando gestiti. Se lasciati manipolati, diventano errori imprevisti.
Errori imprevisti
Gli errori imprevisti (bug) sono stati in cui accade la cosa sbagliata perché il codice è sbagliato. Sai che alla fine accadranno, ma non c'è modo di sapere dove o come gestirli perché, per definizione, sono inaspettati.
Queste sono cose come la sintassi e gli errori logici. Potresti avere un refuso nel tuo codice, potresti aver chiamato una funzione con parametri errati. Questi non sono in genere recuperabili.
try..catch
Parliamo di try..catch
.
In JavaScript, throw
non è comunemente usato. Se cerchi esempi nel codice, saranno pochi e distanti tra loro e di solito strutturati lungo le linee di
function example(param) {
if (!Array.isArray(param) {
throw new TypeError('"param" should be an array!');
}
...
}
Per questo try..catch
motivo , neanche i blocchi sono così comuni per il flusso di controllo. Di solito è abbastanza facile aggiungere alcuni controlli prima di chiamare i metodi per evitare errori previsti.
Anche gli ambienti JavaScript sono abbastanza indulgenti, quindi anche gli errori imprevisti vengono lasciati non rilevati.
try..catch
non deve essere insolito. Ci sono alcuni casi d'uso simpatici, che sono più comuni in linguaggi come Java e C #. Java e C # hanno il vantaggio di catch
costrutti tipizzati , in modo da poter distinguere tra errori previsti e imprevisti:
C # :
try
{
var example = DoSomething();
}
catch (ExpectedException e)
{
DoSomethingElse(e);
}
Questo esempio consente ad altre eccezioni impreviste di fluire e di essere gestite altrove (ad esempio registrandosi e chiudendo il programma).
In JavaScript, questo costrutto può essere replicato tramite:
try {
let example = doSomething();
} catch (e) {
if (e instanceOf ExpectedError) {
DoSomethingElse(e);
} else {
throw e;
}
}
Non così elegante, il che è parte del motivo per cui è raro.
funzioni
Parliamo di funzioni.
Se usi il principio della responsabilità singola , ogni classe e funzione dovrebbe servire a uno scopo singolare.
Ad esempio authenticate()
potrebbe autenticare un utente.
Questo potrebbe essere scritto come:
const user = authenticate();
if (user == null) {
// keep doing stuff
} else {
// handle expected error
}
In alternativa potrebbe essere scritto come:
try {
const user = authenticate();
// keep doing stuff
} catch (e) {
if (e instanceOf AuthenticationError) {
// handle expected error
} else {
throw e;
}
}
Entrambi sono accettabili.
promesse
Parliamo di promesse.
Le promesse sono una forma asincrona di try..catch
. Chiama new Promise
o Promise.resolve
avvia il tuo try
codice. Chiamata throw
o Promise.reject
invio al catch
codice.
Promise.resolve(value) // try
.then(doSomething) // try
.then(doSomethingElse) // try
.catch(handleError) // catch
Se si dispone di una funzione asincrona per autenticare un utente, è possibile scriverlo come:
authenticate()
.then((user) => {
if (user == null) {
// keep doing stuff
} else {
// handle expected error
}
});
In alternativa potrebbe essere scritto come:
authenticate()
.then((user) => {
// keep doing stuff
})
.catch((e) => {
if (e instanceOf AuthenticationError) {
// handle expected error
} else {
throw e;
}
});
Entrambi sono accettabili.
annidamento
Parliamo di nidificazione.
try..catch
può essere nidificato. Il tuo authenticate()
metodo potrebbe avere internamente un try..catch
blocco come:
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
}
}
Allo stesso modo le promesse possono essere nidificate. Il tuo authenticate()
metodo asincrono potrebbe utilizzare internamente le promesse:
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
}
});
Quindi qual è la risposta?
Ok, penso che sia tempo per me di rispondere effettivamente alla domanda:
Un errore nell'autenticazione è considerato qualcosa per cui rifiuteresti una promessa?
La risposta più semplice che posso dare è che dovresti rifiutare una promessa ovunque dovresti altrimenti fare throw
un'eccezione se fosse un codice sincrono.
Se il flusso di controllo è più semplice con alcuni if
controlli nelle then
dichiarazioni, non è necessario rifiutare una promessa.
Se il tuo flusso di controllo è più semplice rifiutando una promessa e quindi controllando la presenza di tipi di errori nel tuo codice di gestione degli errori, fallo invece.
reject
e non restituire false, ma se ti aspetti che il valore sia aBool
, allora hai avuto successo e dovresti risolvere con il Bool indipendentemente dal valore. Le promesse sono una specie di proxy per i valori: memorizzano il valore restituito, quindi solo se il valore non può essere ottenuto dovrestireject
. Altrimenti dovrestiresolve
.