---
title: "Chapitre 3 : Programmation Asynchrone"
weight: 330
---

# 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

```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

```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()

```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

```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

```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

```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

```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)

```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)

```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

```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

```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
```

```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

```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)

```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

```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()` :

```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 :**

```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 :

```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 :**

```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](/training/module1-javascript-es6/fonctions) | [Retour au module](/training/module1-javascript-es6) | [Chapitre suivant : Modules ES6 ->](/training/module1-javascript-es6/modules-es6)
