
async/await
. Pour finir en beauté, nous analyserons une fonction getContent
optimisée qui illustre une approche moderne et efficace pour charger des données de manière dynamique.
1. L'Ancienne École : Les Callbacks 👹
javaScript
import { readFile } from 'fs';
readFile('./mon-fichier.txt', 'utf8', (error, data) => {
if (error) {
console.error("Oups, une erreur est survenue :", error);
return;
}
console.log(data);
});
javaScript
operation1(..., (err, data) => {
// Niveau 1
operation2(..., (err, data) => {
// Niveau 2
operation3(..., (err, data) => {
// Niveau 3
// Et ainsi de suite... nested hell
});
});
});
2. Une Lueur d'Espoir : Les Promises (Promesses) ✨
- Pending : L'opération n'est pas encore terminée.
- Fulfilled (Tenue) ✅ : L'opération a réussi et a retourné une valeur.
- Rejected (Rejetée) ❌ : L'opération a échoué.
.then()
pour les succès et gérer toutes les erreurs en un seul endroit avec .catch()
.
Schéma de l'enchaînement des Promises :
Plain Text
Promesse
|
.then( résultat => ... ) // Succès
|
.then( résultat => ... ) // Succès
|
.catch( erreur => ... ) // Gestion de n'importe quelle erreur dans la chaîne
javaScript
import { promises as fs } from 'fs';
fs.readFile('./mon-fichier.txt', 'utf8')
.then(data => {
console.log("Contenu du fichier :", data);
return fs.writeFile('./copie.txt', data); // On retourne une nouvelle promesse
})
.then(() => {
console.log("Le fichier a été copié avec succès ! 🎉");
})
.catch(error => {
console.error("Une erreur est survenue durant le processus :", error);
});
3. La Révolution : async/await
🪄
async/await
est une surcouche syntaxique aux Promises qui rend le code asynchrone presque aussi lisible que du code synchrone. C'est la méthode à privilégier aujourd'hui.
-
Le mot-clé
async
se place devant une fonction pour indiquer qu'elle retourne une promesse. -
Le mot-clé
await
se place devant une opération qui retourne une promesse. Il met en pause l'exécution de la fonctionasync
jusqu'à ce que la promesse soit résolue, sans pour autant bloquer le reste de l'application.
async/await
:
javaScript
async function() {
try {
const resultat1 = await operation1(); // Attente...
const resultat2 = await operation2(); // Attente...
const resultat3 = await operation3(); // Attente...
// C'est simple et linéaire !
} catch (erreur) {
// Gestion de n'importe quelle erreur
}
}
async/await
💻
javaScript
import { promises as fs } from 'fs';
async function lireEtCopierFichier() {
try {
const data = await fs.readFile('./mon-fichier.txt', 'utf8');
console.log("Contenu du fichier :", data);
await fs.writeFile('./copie.txt', data);
console.log("Le fichier a été copié avec succès ! 🎉");
} catch (error) {
console.error("Une erreur est survenue durant le processus :", error);
}
}
lireEtCopierFichier();
4. Un Cas Pratique : Une Fonction getContent
Optimisée 🏎️
async/await
pour charger dynamiquement plusieurs "morceaux" de contenu.
Analyse de la fonction
-
Signature
async
: La fonction est déclaréeasync
, elle retourne donc implicitement une promesse. -
Importations Dynamiques
import()
: C'est la clé !import()
est une fonction qui retourne une promesse, permettant de charger un module JavaScript de manière asynchrone. -
Gestion d'Erreur Robuste : Le bloc
try...catch
englobe toutes les opérations. Si une seule importation échoue (par exemple,hero.ts
n'existe pas 🔥), l'exécution saute directement au bloccatch
. -
Pattern de Retour
[data, error]
: La fonction retourne un tableau. Soit[données, null]
en cas de succès, soit[null, erreur]
en cas d'échec.
Une Piste d'Optimisation : La Parallélisation avec Promise.all
await
sont séquentiels. C'est sûr, mais pas optimal. Puisque les fichiers sont indépendants, on peut les charger tous en même temps avec Promise.all
.
Schéma : Séquentiel vs Parallèle
Plain Text
// Séquentiel (await l'un après l'autre)
[Tâche 1]--temps-->[Tâche 2]--temps-->[Tâche 3]--temps-->[ FIN ]
Temps total = T1 + T2 + T3
// Parallèle (Promise.all)
|--[Tâche 1]--temps--|
|--[Tâche 2]----temps----|
|--[Tâche 3]---temps---|
|--> [ FIN ]
Temps total = Temps de la tâche la plus longue
typeScript
// ... mêmes définitions de types
export default async function getOptimizedContent(pathArray: string[]): Promise<[any, null] | [null, any]> {
const filePath = `./${pathArray.join('/')}/`;
try {
// 1. On lance toutes les importations en parallèle
const promiseSeo = import(`${filePath}seo.ts`);
const promiseCards = import(`${filePath}cards.ts`);
const promiseServices = import(`${filePath}services.ts`);
const promiseHero = import(`${filePath}hero.ts`);
// 2. On attend que TOUTES les promesses soient résolues
const [
{ seo },
{ cards },
{ services },
{ hero }
] = await Promise.all([promiseSeo, promiseCards, promiseServices, promiseHero]);
// 3. On assemble le résultat
const success = { cards, services, hero, seo };
return [success, null];
} catch (error) {
console.error(`Failed to load module at ${filePath}:`, error);
return [null, error];
}
}
Conclusion
async/await
ont rendu le code infiniment plus propre, lisible et maintenable.
En maîtrisant des outils comme les importations dynamiques et Promise.all
, vous pouvez non seulement écrire du code robuste, mais aussi l'optimiser pour offrir des performances maximales.
Foire Aux Questions (FAQ)
await bloque-t-il mon application Node.js ?
Quelle est la différence entre Promise.all et Promise.allSettled ?
Dois-je toujours utiliser async/await ?
Pourquoi le pattern de retour [data, error] est-il utile ?
Powered by wisp