En JavaScript, de nombreuses opérations sont asynchrones :
Contrairement à PHP où le code s'exécute ligne par ligne, JavaScript peut lancer une opération et continuer sans attendre le résultat.
// 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)
Une Promise représente une valeur qui sera disponible dans le futur.
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); });
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 est une syntaxe plus lisible pour travailler avec les Promises.
// 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; };
await ne peut être utilisé que dans une fonction asyncasync retourne toujours une Promiseawait “pause” l'exécution jusqu'à ce que la Promise soit résolue// 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; }
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; } }
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); } };
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 }
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 - é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: ... } // ]
// 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 - 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
// 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); }
// 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); }
// 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); } }
Convertir ce code utilisant .then() :
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 :
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; } }
Optimiser ce code pour exécuter les requêtes en parallèle :
async function loadDashboard(userId) { const user = await fetchUser(userId); const orders = await fetchOrders(userId); const notifications = await fetchNotifications(userId); return { user, orders, notifications }; }
Solution :
async function loadDashboard(userId) { const [user, orders, notifications] = await Promise.all([ fetchUser(userId), fetchOrders(userId), fetchNotifications(userId) ]); return { user, orders, notifications }; }
← Chapitre précédent | Retour au module | Chapitre suivant : Modules ES6 →