Question 1Qu'affiche try { console.log(1); } finally { console.log(2); } ?
Intercepter les exceptions — try / catch / finally
Intercepte les exceptions avec try et catch, nettoie dans finally, relance avec throw et distingue les erreurs par type.
Quand tu convertis en objet une chaîne reçue, avec JSON.parse, il suffit d'un seul caractère de travers pour que l'exécution s'arrête sur cette ligne : le code d'affichage et d'enregistrement écrit en dessous ne s'exécute jamais. Et tu ne peux pas non plus écarter à l'avance toutes les causes possibles avec des if.
Cet article couvre try / catch, qui intercepte l'exception qui a arrêté ton code, et finally, qui s'exécute dans tous les cas.
Intercepter une exception — try et catch
Prenons une chaîne de paramètres reçue d'un serveur, que tu veux convertir en objet puis appliquer à la page. Si la chaîne est mal formée, JSON.parse lève une exception (une erreur qui interrompt le traitement) sur cette ligne, et aucune des lignes suivantes ne s'exécute. La page reste vide, et il ne se passe rien d'autre.
Quand une exception est levée dans try (un bloc qui entoure du code susceptible d'échouer), l'exécution passe à catch (un bloc qui reçoit l'exception). Dans catch (error), error est simplement le nom que tu donnes à la valeur reçue (err ou n'importe quel autre nom fonctionne tout aussi bien). Cette valeur contient name, le nom du type d'erreur, et message, une description du problème.
// Une chaîne qui garde une virgule finale en trop
const configText = '{"theme":"dark","fontSize":14,}';
try {
const config = JSON.parse(configText);
console.log(config.theme); // cette ligne ne s'exécute pas
} catch (error) {
// l'exécution arrive ici quand une exception est levée
console.log("Impossible de charger les paramètres"); // Impossible de charger les paramètres
console.log(error.name); // SyntaxError
}
// grâce au catch, les lignes suivantes s'exécutent quand même
console.log("Affichage avec les paramètres par défaut"); // Affichage avec les paramètres par défaut
Une fois passée dans catch, l'exécution ne revient jamais terminer la ligne qui a levé l'exception : place donc ton affichage de secours ou ta valeur par défaut dans catch. Le texte de message varie d'un navigateur à l'autre ; lis plutôt name quand tu dois distinguer les types d'erreur.
Exécuter du code en cas de succès comme d'échec — finally
Les tâches de nettoyage, comme masquer un indicateur de chargement ou fermer une connexion ouverte, sont nécessaires que l'opération réussisse ou échoue. Si tu écris la même ligne dans try et dans catch, tu risques plus tard de corriger une copie et d'oublier l'autre, et les deux chemins ne se comportent plus de la même façon.
finally (un bloc qui s'exécute toujours quand on quitte try) se place après catch. Que try soit allé jusqu'au bout ou que catch ait reçu une exception, il s'exécute toujours juste avant la sortie. Tu peux aussi omettre catch et n'écrire que try et finally.
function loadReport(text) {
try {
const report = JSON.parse(text);
console.log(report.title);
} catch (error) {
console.log("Échec du chargement");
} finally {
// s'exécute toujours quand on quitte try
console.log("Indicateur de chargement masqué");
}
}
// En cas de succès
loadReport('{"title":"Ventes de septembre"}'); // Ventes de septembre → Indicateur de chargement masqué
// En cas d'échec
loadReport('{"title":}'); // Échec du chargement → Indicateur de chargement masqué
finally s'exécute une fois que le code de try ou de catch est terminé. C'est pour ça que, dans le code ci-dessus, le message de nettoyage apparaît après le titre en cas de succès, et après le message d'échec en cas d'échec.
Les variables déclarées dans try ne sont pas lisibles en dehors
Une variable déclarée avec const ou let dans try ne s'utilise qu'à l'intérieur de ce bloc. La lire depuis catch, finally ou une ligne située après l'instruction entière lève une ReferenceError. Déclare avec let avant try les valeurs dont tu auras besoin plus tard, et contente-toi de les affecter dans try.
Prévenir l'appelant — throw dans catch
Imagine une fonction qui lit des données de réservation, intercepte une exception et se contente de l'afficher dans le journal. La fonction se termine alors normalement : l'appelant ne remarque pas l'échec, continue d'utiliser la valeur renvoyée, et le code s'arrête de nouveau sur une autre ligne, loin de la vraie cause.
Si tu passes directement l'error reçue par catch à throw (une instruction qui lève une exception), la même exception est transmise à l'appelant. La fonction peut ainsi consigner l'échec elle-même tout en laissant l'appelant décider de la suite.
function readEntry(text) {
try {
return JSON.parse(text);
} catch (error) {
console.log(`Impossible de lire la réservation : ${error.name}`);
throw error; // relance l'exception reçue telle quelle
}
}
try {
const entry = readEntry('{"name":"Léa","seats":}');
console.log(entry.name); // cette ligne ne s'exécute pas
} catch (error) {
console.log("Réservation annulée"); // Réservation annulée
}
Si l'appelant doit lui aussi réagir à une exception interceptée dans une fonction, relance-la en écrivant throw error; à la fin de catch. Les lignes après throw ne s'exécutent pas : place donc ta ligne de journalisation avant.
Un catch vide fait disparaître l'échec
Si tu laisses catch (error) { } vide, l'exception semble s'évanouir, mais l'échec n'est enregistré nulle part et tu ne pourras pas retrouver la cause plus tard. Le résultat le plus courant : une page qui reste simplement vide. Fais toujours au moins une de ces trois choses : afficher un message, revenir à une valeur par défaut ou relancer l'exception.
Distinguer les erreurs par type — instanceof et name
catch reçoit toutes les exceptions, quel que soit leur type. Pourtant, le message à montrer à l'utilisateur n'est pas le même selon que les données étaient mal formées ou qu'une valeur à lire était absente.
instanceof (un opérateur qui vérifie si la valeur de gauche a été créée à partir du type de droite) te permet de vérifier le type, comme dans error instanceof SyntaxError. error.name contient aussi le nom du type sous forme de chaîne.
const applicant = { name: "Alice", contact: null };
try {
console.log(applicant.contact.email);
} catch (error) {
if (error instanceof SyntaxError) {
console.log("Le format des données est invalide"); // on n'arrive pas ici
} else if (error instanceof TypeError) {
console.log("La valeur à lire est absente"); // La valeur à lire est absente
} else {
console.log(`Type d'erreur inattendu : ${error.name}`);
}
console.log(error.name); // TypeError
}
catch (error), mais chacune a un name différent. Vérifier le type permet d'afficher des messages différents.Les exceptions qui ne correspondent à aucune vérification sont toutes interceptées par le else final. Le tableau ci-dessous présente quatre types que tu rencontreras souvent, et les situations où chacun est levé.
| Type | Quand il est levé | Exemple de code qui le lève |
|---|---|---|
| SyntaxError | La chaîne n'est pas au format JSON | JSON.parse("{,}") |
| TypeError | Tu lis une propriété de null ou de undefined | applicant.contact.email |
| RangeError | Tu passes une valeur hors de la plage autorisée, comme un nombre de chiffres | (1980).toFixed(200) (100 chiffres au maximum) |
| ReferenceError | Tu lis un nom qui n'a jamais été déclaré | console.log(total) |
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Si le catch d'une fonction se contente d'afficher un message sans contenir throw error;, quelle valeur l'appelant reçoit-il ?
Question 3Quel opérateur utilises-tu pour vérifier le type de l'error reçue par catch ?