Comment déboguer les erreurs async/await en TypeScript ?

Je travaille sur une API Node.js avec TypeScript et depuis quelques semaines j'ai des problèmes avec async/await. Les Promises ne se résolvent pas correctement d'une manière ou d'une autre et j'obtiens des messages d'erreur cryptiques qui ne m'aident pas vraiment. Comment s'y prendre au mieux pour déboguer ça ?

5 réponses

★ Meilleure réponse

Le problème vient généralement pas de async/await lui-même, mais du fait qu'on ne voit pas vraiment les erreurs - parce qu'elles finissent dans le mauvais scope ou parce qu'une Promise est silencieusement rejetée en arrière-plan.

C'est arrivé récemment : j'avais une fonction qui faisait plusieurs appels API en parallèle, et l'un d'eux a échoué. J'ai d'abord supposé que mon code await était cassé, mais au final c'était juste que je n'avais pas loggé l'erreur. Donc : mets des `.catch()` partout, même sur les Promises que tu "ne besoin pas", et logge agressivement avec `console.error()` ou un Logger - donne le contexte complet à l'erreur. Ça aide beaucoup plus que de lire les Stack Traces. Et vérifie toujours si tu utilises Promise.all() ou Promise.race() quelque part - elles peuvent aussi te piéger si une Promise échoue silencieusement.

Les "messages d'erreur cryptiques" ne sont généralement pas si cryptiques que ça - tu dois juste savoir où chercher. Écris tes fonctions async avec des blocs `.catch()` explicites au lieu de seulement try-catch, et affiche la stack d'erreur complète, pas seulement le message. Utilise aussi le débogueur Node.js ou Chrome DevTools pour parcourir tes Promises étape par étape - tu verras tout de suite où une Promise reste bloquée ou ne se résout pas du tout. Une erreur fréquente, c'est aussi d'oublier `await` ou de lancer accidentellement des Promises sans `await` ; avec `eslint-plugin-promise`, tu attrapes ce genre de choses automatiquement.

Lors du débogage async/await en TypeScript, la Stack Trace est ton meilleur ami - mais tu dois savoir la lire correctement. Si une Promise reste en attente non résolue, commence par vérifier si tu n'as pas oublié `await` quelque part. Ça arrive plus souvent qu'on ne le pense : tu appelles une fonction async, mais tu n'attends pas le résultat. C'est aussi souvent le cas avec `.map()` ou `.forEach()` - les callbacks sont async, mais la map elle-même n'attend rien. Là, `Promise.all()` ou `for...of` à la place des méthodes Array font l'affaire.

Un autre point important : regarde ta stratégie de gestion d'erreurs. Si tu as seulement du try-catch et que le message d'erreur a toujours l'air cryptique, log l'objet Error complet, pas juste le message. `console.log(error)` au lieu de `console.log(error.message)` montre souvent beaucoup plus de contexte. Et c'est vraiment important - en Node.js, il y a des Promise Rejections non gérées qui meurent simplement en arrière-plan. Active l'événement listener `process.on('unhandledRejection', ...)` pour déboguer, tu verras alors où les promises échouent vraiment.

Un conseil pratique : utilise TypeScript lui-même comme outil de débogage. Si tes annotations de type sont correctes, le compilateur TypeScript te dira déjà si tu as oublié d'attendre - tu obtiens des erreurs de type au lieu de surprises à l'exécution. Ça te fait gagner du temps de débogage.

une astuce pratique que j'utilise : log le temps et le contexte avant et après chaque await. comme ça tu vois tout de suite où ça traîne ou où ça prend une éternité. `console.time('myFunc')` avant la fonction async, puis `console.timeEnd('myFunc')` après. ça semble bête, mais ça te montre souvent direct où est le goulot d'étranglement - parfois c'est des dépendances qui prennent un temps fou, pas ton code.

encore plus important : utilise `Promise.all()` ou `Promise.allSettled()` quand tu lances plusieurs promises en parallèle. `allSettled` c'est de l'or en barre, parce que tu vois exactement quelles promises échouent et lesquelles passent - au lieu d'en avoir une qui meurt tôt et les autres qui sont ignorées. avec `allSettled` tu reçois pour chaque promise un objet avec le statut et la valeur/raison, là tu vois précisément où ça coince.

et un hack que beaucoup oublient : ajoute `"lib": ["es2020"]` (ou plus récent) dans ton tsconfig.json et utilise correctement l'optional chaining et le nullish coalescing avec les résultats de promises. mais franchement - mets aussi des statements `debugger;` directement dans tes fonctions async et lance node avec `--inspect`. ensuite tu ouvres chrome://inspect et tu debugges en direct. là tu vois la stack d'appels complète et tu peux vérifier étape par étape où les promises se bloquent. c'est vrai que c'est plus lourd que les logs, mais si les logs ne t'aident pas, c'est la bonne approche.

Oublie tous les blocs `.catch()` à côté de try-catch, ça rend le truc juste incompréhensible - reste sur une seule stratégie. Ce qui aide vraiment : active les événements `unhandledRejection` dans ton app Node (`process.on('unhandledRejection', ...)`) et enregistre tout là-dedans, sinon tes Promises meurent en silence. Ensuite écris temporairement un petit utility wrapper qui enveloppe chaque fonction async avec du logging - tu notes le timestamp et la fonction avant l'await, puis encore après, et tu vois immédiatement si quelque chose bloque ou traîne. Le `console.time()` fonctionne, mais c'est trop granulaire pour les grosses fonctions ; quelques `console.log('avant await X')` placés stratégiquement sont utiles au début.

Votre réponse

Se connecterpour répondre.