Aller au contenu principal

Module JS.8 – Asynchrone

Objectif

Maîtriser la programmation asynchrone JavaScript : setTimeout, Promises, async/await pour gérer les opérations non-bloquantes efficacement.

Théorie

setTimeout et setInterval

setTimeout

Exécute une fonction après un délai.

setTimeout(() => {
console.log("Après 1 seconde");
}, 1000);

// Avec paramètres
setTimeout((nom, age) => {
console.log(`${nom} a ${age} ans`);
}, 1000, "Jean", 30);

Annuler :

const timerId = setTimeout(() => {
console.log("Ne s'affichera pas");
}, 1000);

clearTimeout(timerId); // Annule l'exécution

setInterval

Exécute une fonction à intervalles réguliers.

const intervalId = setInterval(() => {
console.log("Toutes les secondes");
}, 1000);

// Arrêter
clearInterval(intervalId);

Callbacks et Callback Hell

Problème du callback hell :

chargerDonnees((donnees) => {
traiterDonnees(donnees, (resultat) => {
sauvegarder(resultat, (succes) => {
if (succes) {
afficherNotification(() => {
// Encore plus profond...
});
}
});
});
});

Solution : Promises

Promises

Une Promise représente une valeur qui sera disponible dans le futur.

Création

const promesse = new Promise((resolve, reject) => {
// Opération asynchrone
setTimeout(() => {
const succes = true;
if (succes) {
resolve("Données chargées");
} else {
reject(new Error("Échec"));
}
}, 1000);
});

Utilisation

promesse
.then((resultat) => {
console.log(resultat); // "Données chargées"
return "Traitement terminé";
})
.then((message) => {
console.log(message); // "Traitement terminé"
})
.catch((erreur) => {
console.error("Erreur :", erreur);
})
.finally(() => {
console.log("Toujours exécuté");
});

Chaînage

chargerDonnees()
.then(traiterDonnees)
.then(sauvegarder)
.then(afficherNotification)
.catch(gérerErreur);

Méthodes statiques

Promise.all : Attend que toutes les promises se résolvent

const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);

Promise.all([p1, p2, p3])
.then((valeurs) => {
console.log(valeurs); // [1, 2, 3]
});

Promise.allSettled : Attend toutes, même les échecs

Promise.allSettled([p1, p2, p3])
.then((resultats) => {
// Tous les résultats, même les rejetés
});

Promise.race : Retourne la première résolue

Promise.race([p1, p2, p3])
.then((premiere) => {
console.log(premiere); // La première résolue
});

Promise.resolve/reject :

Promise.resolve("Valeur");  // Promise résolue immédiatement
Promise.reject(new Error("Erreur")); // Promise rejetée

async/await

Syntaxe moderne pour gérer les Promises de manière synchrone.

async

Une fonction async retourne toujours une Promise.

async function chargerDonnees() {
return "Données chargées";
}

// Équivalent à :
function chargerDonnees() {
return Promise.resolve("Données chargées");
}

await

await pause l'exécution jusqu'à ce que la Promise soit résolue.

async function processus() {
try {
const donnees = await chargerDonnees();
console.log(donnees);

const traitees = await traiterDonnees(donnees);
console.log(traitees);
} catch (erreur) {
console.error("Erreur :", erreur);
}
}

Avantages :

  • Code plus lisible (semble synchrone)
  • Gestion d'erreurs avec try/catch
  • Pas de callback hell

await avec Promise.all

async function chargerTout() {
const [donnees1, donnees2, donnees3] = await Promise.all([
chargerDonnees1(),
chargerDonnees2(),
chargerDonnees3()
]);

// Toutes chargées en parallèle
}

Fetch API

API moderne pour faire des requêtes HTTP.

fetch('https://api.exemple.com/data')
.then(response => {
if (!response.ok) {
throw new Error('Erreur HTTP');
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(erreur => {
console.error(erreur);
});

Avec async/await :

async function chargerAPI() {
try {
const response = await fetch('https://api.exemple.com/data');

if (!response.ok) {
throw new Error('Erreur HTTP');
}

const data = await response.json();
console.log(data);
} catch (erreur) {
console.error(erreur);
}
}

POST avec données :

async function envoyerDonnees(donnees) {
const response = await fetch('https://api.exemple.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(donnees)
});

return await response.json();
}

Event Loop

Comprendre comment JavaScript gère l'asynchrone.

Ordre d'exécution :

  1. Code synchrone
  2. Microtasks (Promises, queueMicrotask)
  3. Macrotasks (setTimeout, setInterval, I/O)
console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => console.log('3'));

console.log('4');

// Sortie : 1, 4, 3, 2
// Microtasks avant macrotasks

Exercice

  1. setTimeout/setInterval

    • Créez des timers
    • Testez clearTimeout/clearInterval
    • Comprenez le délai minimum
  2. Promises

    • Créez des Promises
    • Chaînez-les avec then/catch
    • Utilisez Promise.all, race
  3. async/await

    • Convertissez des callbacks en async/await
    • Gèrez les erreurs avec try/catch
    • Utilisez await avec Promise.all
  4. Fetch

    • Faites des requêtes HTTP
    • Gèrez les réponses
    • Testez POST avec données
  5. Event Loop

    • Testez l'ordre d'exécution
    • Comprenez microtasks vs macrotasks
    • Observez le comportement

Quiz

  1. Que retourne une fonction async ?

    • La valeur directement
    • Une Promise
    • undefined
  2. Que fait await ?

    • Crée une Promise
    • Attend la résolution d'une Promise
    • Annule une Promise
  3. Quelle est la différence entre Promise.all et Promise.race ?

    • Aucune différence
    • all attend toutes, race la première
    • race est plus rapide
  4. Que fait fetch() ?

    • Charge un fichier local
    • Fait une requête HTTP
    • Crée une Promise
  5. Dans quel ordre s'exécutent microtasks et macrotasks ?

    • Macrotasks d'abord
    • Microtasks d'abord
    • Ordre aléatoire

Mini défi

Mission : Créer un système de chargement de données asynchrone

Créez un système qui charge et traite des données de manière asynchrone :

Fonctionnalités :

  1. Simulation de chargement

    • chargerDonnee(id, delai) : Simule un chargement avec setTimeout
    • Retourne une Promise avec les données
    • Gère les erreurs aléatoires
  2. Chargement séquentiel

    • chargerSequenciel(ids) : Charge les données une par une
    • Utilise async/await
    • Affiche la progression
  3. Chargement parallèle

    • chargerParallele(ids) : Charge toutes en même temps
    • Utilise Promise.all
    • Compare les temps avec séquentiel
  4. Gestion d'erreurs

    • chargerAvecRetry(fonction, maxTentatives) : Réessaie en cas d'échec
    • Utilise async/await
    • Gère les erreurs gracieusement
  5. Requêtes HTTP réelles

    • Utilisez fetch pour charger des données d'une API publique
    • Gèrez les erreurs HTTP
    • Affichez les résultats

Critères :

  • ✅ Utilisation de Promises
  • ✅ async/await pour la lisibilité
  • ✅ Gestion d'erreurs complète
  • ✅ Comparaison séquentiel vs parallèle
  • ✅ Code propre et documenté

Objectif : Maîtriser la programmation asynchrone JavaScript et créer des applications réactives.


Validation : Vous pouvez passer au module suivant quand vous maîtrisez Promises, async/await et pouvez gérer l'asynchrone efficacement.