JS en gros pt.2 : Asynchrone et promesses, Manip de fichiers (06/02/26)
Info
Avant de manipuler des fichiers, il faut comprendre le fonctionnement des modules qui s'en occuperont, l'asynchrone.
Asynchrone et promesses (promise)
C'est quoi Asynchrone ?
Asynchrone permet de ne pas bloquer le code même si il n'a pas de résultat mais avec promesse, il laisse le code continuer pour trouver une réponse et la rapporter comme promis.
Rien de mieux qu'un exemple concret et gourmand en amont !
1. SANS Asynchrone
- Tu commandes un Tasty Crousty.
- Ce neuille de caissier part en cuisine.
- Il fait cuire le riz lui-même.
- Il coupe les tenders.
- Il met tout dans la barquette puis sauce.
- Et revient pour te donner le Tasty Crousty 67 doro party.
- SEULEMENT MAINTENANT, il prend la commande du gwer suivant.
Résultat : La file d'attente sort du restaurant. Si la cuisson prend 10 minutes, tout le restaurant est bloqué pendant 10 minutes. Bien guez.
2. AVEC Asynchrone
- Tu commandes un Tasty Crouspy.
- La caissière crie en cuisine "Un Crousty piquant sucré supplément poulet !".
- Elle te donne un bipeur, faisant donc la promesse de te servir un délicieux Crouspy Tasty.
- Puis elle passe directement au client suivant.
- Toi, tu vas t'asseoir et tu attends.
Mais c'est quoi cette promesse ? (Promise)
☝️🤓 Node.js fonctionne sur un principe de thread unique (monothread)... En gros, il ne peut effectuer qu'une seule tâche à la fois.
Pour éviter de bloquer le programme pendant de longues opérations (comme lire des données au fin fond du disque dur), il délègue ces tâches a l'ordinateur et utilise un mécanisme de Promesses.
Dans notre exemple, la Promise, c'est le bipeur.
Ce boîtier est une promesse. Le restaurant te dit : "Je n'ai pas ton crousty tout de suite, mais je te promets que je te préviendrai dès qu'il y a du nouveau."
Une Promise a toujours 3 états possibles, et seulement 3 :
- En attente (Pending) : Le boîtier ne fait rien. Le cuisinier travaille. Tu attends.
- Succès (Resolved) : Le boîtier vibre ! La promesse est tenue, tu as ton chicken (la donnée est arrivée).
- Échec (Rejected) : Le manager arrive et te dit "Désolé, la cuisine a pris feu, pas de délicieux crousty pour ce soir". La promesse est rompue (il y a une erreur).
Exemples async et await
Exemple d'un async (exo du TP 2 de JS)
files.forEach((fileName) => {
fs.readFile(fileName, 'utf8').then((content) => {
...
})
});
fs.readFile: Envoie le job de lire un fichier à l'ordinateur avec des parametres et quand c'est pret, enrengistre son résultat danscontent.- La Promise : En lançant fs.readFile, celui-ci promet que dès qu'il a un résultat, il le renverra dans
content
Exemple concret await (exo du TP 2 de JS)
On peut également demander spécifiquement d'attendre le retour d'une promesse avec await
const stats = await fs.stat(filename);
fs.stat: Envoie le job de récupérer les stats d'un fichier à l'ordinateur et quand c'est pret, enrengistre son résultat dansstats.- La Promise : On te promet un résultat dans
stats **await**: Tant que l'on a pas de résultat, on "fige" à cette ligne jusqu'à ce que la promesse est reçue.
Manipulation de fichiers
Pour manipuler des fichiers avec Node.JS, il existe un module appelé Node.JS fs, fs pour fiché S. Avec cette librairie on peut manipuler de plusieurs manière nos fichiers, les lire, écrire ou réécrire, demander les infos d'un fichier, copier et pleinnn de choses encore !
Ici on se concentrera sur les fonctions qu'on utilise dans le TP 2 de JS
Avant tout, pour utiliser ce module, il faut l'appeler via une constante :
const fs = require('fs').promises; // fs prendra l'appel du module en utilisant les promesses de tout à l'heure
Lecture de fichiers (fs.readFile)
Pour lire des fichiers, on utilise la fonction fs.readFile. Lorsque cette commande est exécutée, le moteur JavaScript ne lit pas le fichier lui-même. Il envoie une requête au système d'exploitation (l'OS) pour qu'il s'en charge.
- Concrètement : Le programme libère immédiatement la main. Il ne reste pas bloqué sur cette ligne et continue d'exécuter le code qui suit.
2. La Résolution (Le Callback)
Une fois que le système d'exploitation a fini de lire le fichier, il notifie le programme. La Promesse change d'état et déclenche l'une des deux fonctions suivantes :
-
Le Succès (
.then) : Déclenché si l'opération a réussi. Le système injecte les données lues (le contenu du fichier) dans la fonction définie ici. C'est ici que le traitement des données commence. -
L'Erreur (
.catch) : Déclenché si l'opération a échoué (fichier introuvable, permissions refusées). Le système injecte un objetErrorcontenant les détails du problème. Cela permet de capturer l'exception sans faire planter l'application.
PARTIE 2 : Le Traitement Séquentiel (Le modèle async/await)
Parfois, l'asynchronisme pur est difficile à gérer (besoin d'ordre précis). La syntaxe async/await permet de forcer un comportement séquentiel au sein d'une fonction asynchrone.
1. La Suspension de l'Exécution (await)
Le mot-clé await placé devant une Promesse (comme fs.readFile) modifie le flux d'exécution.
* Concrètement : L'interpréteur met en pause uniquement l'exécution de la fonction actuelle. Il attend que la Promesse soit résolue (terminée) avant de passer à la ligne suivante.
* L'encodage (utf8) : Spécifie au système de convertir directement le flux binaire (Buffer) en chaîne de caractères lisible (String) avant de renvoyer le résultat.
2. Le Mode d'Écriture (appendFile vs writeFile)
Lorsqu'il s'agit d'écrire des données sur le disque, le choix de la méthode détermine comment le fichier est manipulé au niveau basique :
-
fs.writeFile(Écrasement) : Cette méthode ouvre le fichier et place le curseur au tout début (index 0). Si le fichier contient déjà des données, elles sont tronquées (supprimées) et remplacées par le nouveau contenu. -
fs.appendFile(Ajout) : Cette méthode ouvre le fichier et place le curseur directement à la fin du fichier (EOF - End Of File). Les nouvelles données sont écrites à la suite des existantes, préservant ainsi l'historique.
3. L'Itération (La boucle)
Dans un contexte async/await, une boucle permet de traiter une liste d'éléments un par un.
* Concrètement : Le système traite le premier fichier, attend la fin complète de l'opération (lecture + écriture), et seulement ensuite passe à l'itération suivante. Cela garantit l'ordre des opérations.
📝 En Résumé Technique
- I/O Asynchrone : Permet de déléguer les opérations lentes (disque, réseau) au système pour ne pas bloquer le processeur.
- Promise : Objet représentant l'état futur d'une opération (En attente -> Résolu ou Rejeté).
- Flux Séquentiel (
await) : Force le code à attendre la résolution d'une promesse avant de continuer, simulant un code synchrone pour plus de lisibilité et de contrôle. - Gestion d'erreur : Indispensable pour intercepter les exceptions systèmes (I/O) et éviter l'arrêt brutal du processus node.