Menu
Français

try/catch en JavaScript : gérer les erreurs proprement

Comment fonctionnent try, catch et finally en JavaScript : capturer une erreur, relancer, l'objet error, et les cas où try/catch n'est pas la bonne solution.

try/catch, c'est un filet de sécurité, pas une ceinture

Quand une ligne de JavaScript lève une erreur, l'exécution s'arrête net et l'erreur remonte la pile d'appels. Si personne ne l'attrape, le programme plante (côté Node) ou affiche un beau mur rouge dans la console (côté navigateur). Le try/catch sert justement à intercepter tout ça — c'est ta façon de dire « je sais que ça peut foirer, voilà ce que je veux faire à la place ».

La structure de base :

index.js
Output
Click Run to see the output here.

JSON.parse lève une SyntaxError. L'exécution saute immédiatement dans le bloc catch, avec l'erreur récupérée dans err. Le troisième console.log s'exécute quand même — le plantage a bien été contenu.

Si le bloc try se termine sans lever d'exception, le bloc catch est tout simplement ignoré. Il n'est là que pour gérer le cas où ça casse.

L'objet Error en JavaScript

Ce qui est lancé via throw est passé au paramètre nommé dans catch (...). La plupart du temps, c'est une instance d'Error qui expose trois propriétés bien pratiques :

index.js
Output
Click Run to see the output here.

name indique la sous-classe (TypeError, RangeError, SyntaxError, etc. — on y revient dans la prochaine doc). message contient la description lisible par un humain. Quant à stack, c'est la trace complète, et c'est en or au moment de débugger.

Un petit piège : en JavaScript, on peut faire throw avec n'importe quelle valeur, pas seulement avec un objet Error. Dans du vieux code, on voit parfois des trucs du genre throw "something broke". Quand vous écrivez votre propre throw, lancez toujours une instance d'Error pour que l'appelant récupère une stack trace :

index.js
Output
Click Run to see the output here.

Le bloc finally s'exécute dans tous les cas

finally est un troisième bloc optionnel qui s'exécute qu'une erreur ait été levée ou non, et que le catch l'ait gérée ou non. Il sert au nettoyage : fermer des fichiers, libérer des verrous, masquer un indicateur de chargement :

index.js
Output
Click Run to see the output here.

Le spinner est masqué, que le chargement ait réussi ou échoué. Sans finally, il faudrait écrire cette ligne dans les deux branches — et tu finirais forcément par l'oublier dans l'une des deux.

finally s'exécute même si le bloc try ou catch contient un return. La fonction ne retourne qu'après l'exécution de finally. Ça peut surprendre au début, mais c'est presque toujours le comportement qu'on veut.

catch n'est pas toujours obligatoire

Le bloc catch est facultatif. Un simple try/finally est parfaitement valide, et même pratique quand tu veux garantir un nettoyage sans pour autant gérer l'erreur — tu veux juste qu'elle remonte :

index.js
Output
Click Run to see the output here.

Le try/finally interne libère le verrou même si fn() lève une exception, mais sans avaler l'erreur pour autant — l'appelant la voit toujours passer. Avaler les erreurs en silence (« ça a planté mais j'ai rien dit à personne »), c'est l'un des pires cauchemars côté débogage.

Relancer une erreur en JavaScript : gérer certains cas, laisser passer le reste

Un bloc catch n'est pas obligé de tout gérer. Tu peux inspecter l'erreur, traiter ce qui te concerne, et relancer le reste :

index.js
Output
Click Run to see the output here.

Le pattern à retenir, c'est le instanceof : on attrape les erreurs qu'on sait récupérer, et on laisse remonter tout le reste. Avaler chaque erreur avec un catch vide, c'est un vrai code smell — tu perds tout signal dès qu'un truc inattendu se produit.

try/catch avec async/await en JavaScript

Dans une fonction async, une promesse awaitée qui rejette devient une erreur levée — et le try/catch la gère exactement comme une erreur synchrone :

index.js
Output
Click Run to see the output here.

Subtilité importante : il faut bien await la promesse à l'intérieur du bloc try. Si tu renvoies une promesse sans l'attendre, le rejet survient une fois la fonction déjà terminée, et le catch ne le verra jamais :

async function bad() {
  try {
    return fetch("/broken");  // pas de await — l'appelant voit le rejet
  } catch (err) {
    // ne s'exécute jamais
  }
}

Règle simple : dans une fonction async, placez un await devant ce que vous voulez couvrir par votre try/catch.

Try/catch imbriqué en JavaScript

Vous pouvez imbriquer des blocs try/catch quand le code interne et le code externe échouent pour des raisons différentes que vous souhaitez traiter séparément :

index.js
Output
Click Run to see the output here.

Le catch interne gère le cas « la structure des données n'est pas bonne » en renvoyant une valeur par défaut sûre. Le catch externe, lui, s'occupe du cas « l'entrée n'était carrément pas du JSON » : il enveloppe l'erreur et la relance. Imbriquer des try/catch est tout à fait acceptable quand chaque niveau a sa propre stratégie de récupération — mais si les deux blocs font la même chose, mieux vaut aplatir le tout.

Quand ne pas utiliser try/catch

try/catch est un outil pour les erreurs attendues et récupérables. Ce n'est pas un moyen de camoufler des bugs.

  • N'enveloppez pas tout le corps d'une fonction « au cas où ». Si vous n'avez aucun vrai plan pour traiter l'erreur, laissez-la remonter — une erreur non interceptée avec sa pile d'appels est bien plus utile qu'une erreur silencieuse.
  • Ne l'utilisez pas pour piloter le flux d'exécution. Les blocs try ont un vrai coût et rendent le code moins clair qu'un simple if. if (user) est préférable à try { user.name } catch {}.
  • N'attrapez pas une erreur juste pour la logger et l'ignorer. Au minimum, relancez-la ou renvoyez une valeur sentinelle que l'appelant pourra détecter.

Le test mental : « que fait le code appelant quand ça échoue ? ». Si vous n'avez pas de réponse, c'est que vous n'êtes pas encore prêt à catch l'erreur.

Aide-mémoire

  • try { ... } catch (err) { ... } — intercepter les erreurs lancées.
  • finally { ... } — s'exécute toujours ; parfait pour le nettoyage.
  • throw new Error("...") — lancez toujours des sous-classes d'Error pour conserver les traces d'appels.
  • throw err; dans un catch — relancer une erreur quand on ne sait pas la traiter.
  • await à l'intérieur d'un try — indispensable pour que try/catch voie les rejets asynchrones.

Suite : les types d'erreurs

TypeError, RangeError, SyntaxError… JavaScript fournit toute une famille de classes d'erreurs intégrées, et savoir ce que chacune signifie rend l'interception et le reporting bien plus précis. C'est le sujet du prochain chapitre.

Questions fréquentes

Comment fonctionne try/catch en JavaScript ?

On place le code à risque dans try { ... }. Si une exception est levée à l'intérieur, l'exécution saute directement dans catch (err) { ... } avec la valeur levée dans err. Si rien n'est levé, le bloc catch est ignoré. Le bloc finally { ... } est optionnel et s'exécute dans tous les cas — pratique pour le nettoyage (fermeture de ressources, etc.).

Quand utiliser try/catch en JavaScript ?

Autour des opérations qui peuvent réellement échouer à l'exécution : JSON.parse sur une entrée non maîtrisée, une réponse fetch, un accès réseau ou fichier. Inutile d'en mettre partout : si tu n'as aucun plan de récupération, laisse l'erreur remonter. Un try/catch trop large sur du code qui marche masque les bugs au lieu de les traiter.

Est-ce que try/catch attrape les erreurs asynchrones ?

Uniquement si tu fais await sur la promesse à l'intérieur du bloc try. Un simple appel somePromise() sans await ne sera pas capturé — l'erreur finit en unhandled rejection. Avec async/await, try/catch se comporte comme en synchrone. Pour des promesses brutes, passe plutôt par .catch() sur la chaîne.

Comment relancer une erreur en JavaScript ?

Dans le catch, il suffit de faire throw err; (ou de lancer une nouvelle erreur qui encapsule l'originale). C'est utile quand tu veux gérer certains cas et laisser les autres remonter : tu inspectes le type ou le message de l'erreur, tu traites ce que tu peux, et tu relances le reste pour que l'appelant en haut de la pile le voie aussi.

Apprendre à coder avec Coddy

COMMENCER