SmarMaker - Documentation
Docs» 15_training:module1-javascript-es6:asynchrone

Chapitre 3 : Programmation Asynchrone

Introduction

En JavaScript, de nombreuses opérations sont asynchrones :

  • Appels API (fetch)
  • Lecture de fichiers
  • Timers (setTimeout)
  • Accès à la base de données locale (IndexedDB)

Contrairement à PHP où le code s'exécute ligne par ligne, JavaScript peut lancer une opération et continuer sans attendre le résultat.

Le problème

snippet.javascript
// Ce code ne fait pas ce que vous pensez!
console.log("1. Début");
 
setTimeout(() => {
    console.log("2. Dans le timeout");
}, 1000);
 
console.log("3. Fin");
 
// Affiche :
// "1. Début"
// "3. Fin"
// "2. Dans le timeout" (1 seconde plus tard)

Les Promises

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

États d'une Promise

  • pending : en attente
  • fulfilled : résolue avec succès (contient une valeur)
  • rejected : rejetée (contient une erreur)

Créer une Promise

snippet.javascript
const myPromise = new Promise((resolve, reject) => {
    // Opération asynchrone simulée
    setTimeout(() => {
        const success = true;
 
        if (success) {
            resolve("Données reçues"); // Succès
        } else {
            reject(new Error("Échec")); // Erreur
        }
    }, 1000);
});

Consommer une Promise avec .then() et .catch()

snippet.javascript
myPromise
    .then(result => {
        console.log("Succès:", result);
    })
    .catch(error => {
        console.log("Erreur:", error.message);
    });
 
// Chaînage de .then()
fetchUser(1)
    .then(user => fetchPosts(user.id))
    .then(posts => console.log(posts))
    .catch(error => console.log("Erreur:", error));

async/await

async/await est une syntaxe plus lisible pour travailler avec les Promises.

Syntaxe de base

snippet.javascript
// Fonction async
async function fetchData() {
    const response = await fetch("https://api.example.com/data");
    const data = await response.json();
    return data;
}
 
// Arrow function async
const fetchData = async () => {
    const response = await fetch("https://api.example.com/data");
    const data = await response.json();
    return data;
};

Règles importantes

  1. await ne peut être utilisé que dans une fonction async
  2. Une fonction async retourne toujours une Promise
  3. await “pause” l'exécution jusqu'à ce que la Promise soit résolue

Exemple comparatif

snippet.javascript
// Avec .then()
function getUserPosts(userId) {
    return fetchUser(userId)
        .then(user => fetchPosts(user.id))
        .then(posts => {
            console.log(posts);
            return posts;
        });
}
 
// Avec async/await (plus lisible)
async function getUserPosts(userId) {
    const user = await fetchUser(userId);
    const posts = await fetchPosts(user.id);
    console.log(posts);
    return posts;
}

Gestion des erreurs

Avec try/catch

snippet.javascript
async function fetchData() {
    try {
        const response = await fetch("https://api.example.com/data");
 
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
        }
 
        const data = await response.json();
        return data;
 
    } catch (error) {
        console.error("Erreur:", error.message);
        // Gérer l'erreur (afficher un message, retourner une valeur par défaut, etc.)
        return null;
    }
}

Pattern courant en React

snippet.javascript
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
 
const loadData = async () => {
    setLoading(true);
    setError(null);
 
    try {
        const response = await fetch("/api/items");
        const result = await response.json();
        setData(result);
    } catch (err) {
        setError(err.message);
    } finally {
        setLoading(false);
    }
};

Exécution parallèle vs séquentielle

Séquentiel (un après l'autre)

snippet.javascript
async function sequential() {
    const user = await fetchUser(1);      // Attend...
    const posts = await fetchPosts(1);    // Puis attend...
    const comments = await fetchComments(1); // Puis attend...
 
    // Temps total = temps1 + temps2 + temps3
}

Parallèle (en même temps)

snippet.javascript
async function parallel() {
    // Lance les 3 requêtes en même temps
    const [user, posts, comments] = await Promise.all([
        fetchUser(1),
        fetchPosts(1),
        fetchComments(1)
    ]);
 
    // Temps total = max(temps1, temps2, temps3)
}

Promise.all vs Promise.allSettled

snippet.javascript
// Promise.all - échoue si UNE promise échoue
try {
    const results = await Promise.all([promise1, promise2, promise3]);
} catch (error) {
    // Une des promises a échoué
}
 
// Promise.allSettled - attend toutes, même si certaines échouent
const results = await Promise.allSettled([promise1, promise2, promise3]);
// results = [
//   { status: "fulfilled", value: ... },
//   { status: "rejected", reason: Error },
//   { status: "fulfilled", value: ... }
// ]

Comparaison avec PHP

snippet.php
// PHP - synchrone par défaut
$user = file_get_contents("https://api.example.com/user/1");
$posts = file_get_contents("https://api.example.com/posts/1");
// Chaque ligne attend que la précédente soit terminée
snippet.javascript
// JavaScript - asynchrone
const user = await fetch("https://api.example.com/user/1");
const posts = await fetch("https://api.example.com/posts/1");
// Similaire grâce à await, mais sous le capot c'est asynchrone

Pièges courants

1. Oublier await

snippet.javascript
// INCORRECT
async function getData() {
    const data = fetch("/api/data"); // Oublié await!
    console.log(data); // Promise { <pending> } - pas les données!
}
 
// CORRECT
async function getData() {
    const response = await fetch("/api/data");
    const data = await response.json();
    console.log(data);
}

2. await dans une boucle (séquentiel non voulu)

snippet.javascript
// LENT - chaque itération attend la précédente
async function slow() {
    for (const id of ids) {
        const data = await fetchItem(id); // Séquentiel!
    }
}
 
// RAPIDE - toutes les requêtes en parallèle
async function fast() {
    const promises = ids.map(id => fetchItem(id));
    const results = await Promise.all(promises);
}

3. Ne pas gérer les erreurs

snippet.javascript
// DANGEREUX - erreur non gérée
async function riskyCode() {
    const data = await fetchData(); // Si ça échoue?
}
 
// SÛRE - erreur gérée
async function safeCode() {
    try {
        const data = await fetchData();
    } catch (error) {
        console.error("Erreur gérée:", error);
    }
}

Exercices

Exercice 1 : Convertir en async/await

Convertir ce code utilisant .then() :

snippet.javascript
function getUser(id) {
    return fetch(`/api/users/${id}`)
        .then(response => response.json())
        .then(user => {
            console.log(user);
            return user;
        })
        .catch(error => {
            console.error("Erreur:", error);
            return null;
        });
}

Solution :

snippet.javascript
async function getUser(id) {
    try {
        const response = await fetch(`/api/users/${id}`);
        const user = await response.json();
        console.log(user);
        return user;
    } catch (error) {
        console.error("Erreur:", error);
        return null;
    }
}

Exercice 2 : Parallélisation

Optimiser ce code pour exécuter les requêtes en parallèle :

snippet.javascript
async function loadDashboard(userId) {
    const user = await fetchUser(userId);
    const orders = await fetchOrders(userId);
    const notifications = await fetchNotifications(userId);
 
    return { user, orders, notifications };
}

Solution :

snippet.javascript
async function loadDashboard(userId) {
    const [user, orders, notifications] = await Promise.all([
        fetchUser(userId),
        fetchOrders(userId),
        fetchNotifications(userId)
    ]);
 
    return { user, orders, notifications };
}

Points clés à retenir

  1. Promise : représente une valeur future (pending → fulfilled/rejected)
  2. async/await : syntaxe lisible pour les Promises
  3. await : “pause” l'exécution jusqu'à résolution
  4. try/catch : gestion des erreurs avec async/await
  5. Promise.all : exécuter plusieurs Promises en parallèle
  6. Toujours gérer les erreurs avec try/catch

← Chapitre précédent | Retour au module | Chapitre suivant : Modules ES6 →

Previous Next

Made with ❤ by CAP-REL · SmartMaker · GNU AGPL v3+
Code source · Faire un don
SmarMaker - Documentation
Traductions de cette page:
  • Français
  • Deutsch
  • English
  • Español
  • Italiano
  • Nederlands

Table of Contents

Table des matières

  • Chapitre 3 : Programmation Asynchrone
    • Introduction
    • Le problème
    • Les Promises
      • États d'une Promise
      • Créer une Promise
      • Consommer une Promise avec .then() et .catch()
    • async/await
      • Syntaxe de base
      • Règles importantes
      • Exemple comparatif
    • Gestion des erreurs
      • Avec try/catch
      • Pattern courant en React
    • Exécution parallèle vs séquentielle
      • Séquentiel (un après l'autre)
      • Parallèle (en même temps)
      • Promise.all vs Promise.allSettled
    • Comparaison avec PHP
    • Pièges courants
      • 1. Oublier await
      • 2. await dans une boucle (séquentiel non voulu)
      • 3. Ne pas gérer les erreurs
    • Exercices
      • Exercice 1 : Convertir en async/await
      • Exercice 2 : Parallélisation
    • Points clés à retenir
  • SmartAuth
  • SmartMaker - Back (PHP)
    • Mapping Dolibarr - React
  • SmartMaker - Front (React)
    • Animations de pages
    • Architecture
    • Astuces
    • Calendar
    • Composants et pages
    • Configuration du Provider
    • Debug et Logs
    • Hooks SmartCommon
    • PWA (Progressive Web App)
    • Requêtes API
    • Routage
    • SmartCommon
    • Stockage de données
    • Thèmes
    • Traductions
  • HowTo - Pas à pas - Votre première application
    • Développement PHP (back)
    • Développement React (front)
    • Première étape : Module Builder Dolibarr
    • SmartAuth
    • SmartBoot : Un "squelette" quasiment prêt à l'emploi
  • Formation SmartMaker
    • Module 1 : Fondamentaux JavaScript ES6+
      • Chapitre 1 : Variables et Scope
      • Chapitre 2 : Fonctions
      • Chapitre 3 : Programmation Asynchrone
      • Chapitre 4 : Modules ES6
    • Module 2 : Introduction à React
      • Chapitre 1 : Philosophie React
      • Chapitre 2 : JSX
      • Chapitre 3 : Composants
    • Module 3 : Hooks React Fondamentaux
      • Chapitre 1 : useState
      • Chapitre 2 : useEffect
      • Chapitre 3 : useRef
      • Chapitre 4 : useContext
    • Module 4 : React Avancé
      • Chapitre 1 : useCallback et useMemo
      • Chapitre 2 : Custom Hooks
      • Chapitre 3 : Redux et Redux Toolkit
    • Module 5 : Architecture SmartMaker
      • Chapitre 1 : Structure du projet
      • Chapitre 2 : Configuration
      • Chapitre 3 : Flux de données
    • Module 6 : SmartCommon - Composants
      • Chapitre 1 : Mise en page
      • Chapitre 2 : Navigation
      • Chapitre 3 : Formulaires
      • Chapitre 4 : Affichage
    • Module 7 : SmartCommon - Hooks
      • Chapitre 1 : useApi
      • Chapitre 2 : Gestion d'état
      • Chapitre 3 : Hooks utilitaires
    • Module 8 : Backend API (PHP)
      • Chapitre 1 : Routage
      • Chapitre 2 : Controllers
      • Chapitre 3 : Mappers
      • Extrafields et formulaires dynamiques
    • Module 9 : Intégration complète
      • Chapitre 1 : Backend
      • Chapitre 2 : Frontend
      • Chapitre 3 : Déploiement
    • Module 10 : Fonctionnalités avancées
      • Chapitre 1 : Mode offline
      • Chapitre 2 : Internationalisation (i18n)
      • Chapitre 3 : Autres fonctionnalités
    • Module 11 : Bonnes pratiques
  • Démonstration
  • Start
  • Composants et pages
  • Afficher le texte source
  • Anciennes révisions
  • Liens de retour
  • Haut de page