Apprenez en lisant dans l'ordre

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
Sans try ou avec try
parse sanstryException levéesur cette ligneAucun catchpour l'intercepterLignes suivantesnon exécutéesparse danstryException levéesur cette lignePasse àcatch (error)Lignes après tryexécutées
Dans les deux cas, la ligne juste sous celle qui a levé l'exception ne s'exécute pas. Avec try, le contrôle passe à catch, puis continue sur les lignes qui suivent le try.

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.

Récupère le titre d'un brouillon enregistré. savedDraft et brokenDraft sont déjà déclarés.

① Dans restoreTitle, convertis la chaîne en objet et renvoie son titre.

② En cas d'échec, affiche le nom du type d'erreur et renvoie « Brouillon sans titre ».

③ Appelle la fonction avec les deux chaînes et affiche chaque résultat sous la forme « Titre : Rapport de septembre ».

(Si tout s'exécute correctement, une explication apparaîtra.)

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat

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é
Deux chemins qui finissent au même endroit
Passer unechaîne validetry vajusqu'au boutcatch estsautéfinallys'exécutePasser une chaînemal forméeException levéeau milieu de trycatch lareçoitfinallys'exécute
Les deux lignes passent par des étapes différentes, mais aboutissent au même bloc. finally s'exécute que le code réussisse ou échoue.

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.

Importe des données de membres ligne par ligne en affichant la progression. rows et processed sont déjà déclarés, et la ligne 2 est mal formée.

① Convertis chaque ligne et affiche-la sous la forme « Alice : formule annuelle ».

② Si la conversion échoue, affiche « Une ligne n'a pas pu être importée ».

③ En cas de succès comme d'échec, ajoute 1 à processed et affiche-le sous la forme « Lignes traitées : 1 / 3 ».

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat

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
}
Relancer ou ne pas relancer
catch contientthrow errorLa SyntaxErrorremonteLe catch externela reçoit« Réservationannulée »catch sansthrow errorLa valeur renvoyéeest undefinedTypeError surentry.nameL'appelant reçoitune autre erreur
Sur la ligne du bas, l'exception est étouffée dans la fonction, et le code échoue de nouveau sur la ligne qui lit undefined. Si tu relances, la SyntaxError d'origine atteint l'appelant.

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.

Charge une mise en page enregistrée. savedLayout, layout et errorLog sont déjà déclarés.

① Dans loadLayout, convertis la chaîne et renvoie le résultat.

② En cas d'échec, ajoute le nom du type d'erreur à errorLog et relance l'exception.

③ Affecte le résultat à layout et, en cas d'échec, affiche « Affichage avec la mise en page par défaut ».

④ Affiche le nombre de colonnes et le journal sous la forme « Colonnes : 2 » et « Journal : SyntaxError ».

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat

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
}
Trois exceptions, un seul catch
Exception levéedans tryparse d'un JSONmal forméLire contactquand il est nullDemander 200chiffres à toFixedname vautSyntaxErrorname vautTypeErrorname vautRangeErrorSignaler unformat invalideSignaler unevaleur absenteLe consignercomme inattendu
Les trois arrivent au même 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é.

TypeQuand il est levéExemple de code qui le lève
SyntaxErrorLa chaîne n'est pas au format JSONJSON.parse("{,}")
TypeErrorTu lis une propriété de null ou de undefinedapplicant.contact.email
RangeErrorTu passes une valeur hors de la plage autorisée, comme un nombre de chiffres(1980).toFixed(200) (100 chiffres au maximum)
ReferenceErrorTu lis un nom qui n'a jamais été déclaréconsole.log(total)

Traite les relevés envoyés sous forme de chaînes par des capteurs de température. payloads est déjà déclaré, et deux des trois posent problème.

① Convertis chaque relevé et affiche-le sous la forme « T-1 : 21.5 degrés », avec la température arrondie à 1 décimale.

② Si le format est cassé, affiche « Le format des données reçues est invalide ».

③ S'il n'y a pas de température, affiche « Aucune température relevée ».

④ Sinon, affiche « Inattendu : » suivi du nom du type d'erreur.

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat
QUIZ

Vérification des connaissances

Répondez à chaque question une par une.

Question 1Qu'affiche try { console.log(1); } finally { console.log(2); } ?

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 ?