{}const=>[]async()letfn</>var
DéveloppementBasesJS

Async/Await : le guide complet du code asynchrone

Nous comprenons comment travailler avec du code asynchrone en utilisant async/await. Apprenez à éviter le callback hell, à gérer correctement les erreurs, à optimiser les opérations parallèles et à appliquer des modèles avancés.

К

Kodik

Auteur

6 min de lecture

Pourquoi avons-nous besoin d'asynchronisme

Imaginez que votre application effectue une requête à une API externe qui répond en 2 secondes. Sans asynchronisme, le programme se bloquera simplement pendant ce temps, bloquant l'exécution d'autres opérations. Le code asynchrone permet à l'application de continuer à fonctionner pendant que l'opération s'exécute en arrière-plan.

🔥 100 000+ étudiants déjà avec nous

Marre de lire la théorie ?
Il est temps de coder !

Kodik — une appli où tu apprends à coder par la pratique. Mentor IA, leçons interactives, projets réels.

🤖 IA 24/7
🎓 Certificats
💰 Gratuit
🚀 Commencer
Ont rejoint aujourd'hui

Des callbacks aux promesses et à l'async/await

L'évolution du code asynchrone en JavaScript a connu plusieurs étapes :

Fonctions de rappel (approche obsolète) :

fetchUser(userId, (error, user) => {
  if (error) {
    console.error(error);
    return;
  }
  fetchPosts(user.id, (error, posts) => {
    if (error) {
      console.error(error);
      return;
    }
    // Le Callback hell commence ici
  });
});

Promesses (amélioration) :

fetchUser(userId)
  .then(user => fetchPosts(user.id))
  .then(posts => console.log(posts))
  .catch(error => console.error(error));

Async/Await (approche moderne) :

async function getUserPosts(userId) {
  try {
    const user = await fetchUser(userId);
    const posts = await fetchPosts(user.id);
    return posts;
  } catch (error) {
    console.error(error);
  }
}

Bases de l'async/await

Le mot-clé async devant la fonction signifie que la fonction renvoie toujours une promesse. Le mot-clé await oblige JavaScript à attendre le résultat de la promesse avant de poursuivre l'exécution.

async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
}

Règles importantes :

  • await ne peut être utilisé qu'à l'intérieur des fonctions async

  • async la fonction renvoie toujours une promesse

  • Si la fonction renvoie une valeur, elle est automatiquement enveloppée dans Promise.resolve()

Traitement des erreurs

Les blocs try-catch sont un moyen naturel de gérer les erreurs dans async/await :

async function processOrder(orderId) {
  try {
    const order = await fetchOrder(orderId);
    const payment = await processPayment(order);
    const confirmation = await sendConfirmation(payment);
    return confirmation;
  } catch (error) {
    if (error.code === 'PAYMENT_FAILED') {
      await refundOrder(orderId);
    }
    throw new Error(`Order processing failed: ${error.message}`);
  }
}

Peut être combiné avec .catch() pour un traitement plus granulaire :

async function getData() {
  const data = await fetchData().catch(error => {
    console.error('Fetch failed:', error);
    return getDefaultData(); // Restauration des données par défaut
  });
  return data;
}

Exécution parallèle

Une des erreurs fréquentes est l'exécution séquentielle d'opérations indépendantes :

// Mauvais : les opérations sont effectuées de manière séquentielle (6 secondes)
async function loadData() {
  const users = await fetchUsers(); // 3 secondes
  const posts = await fetchPosts(); // 3 secondes
  return { users, posts };
}

Utilisez Promise.all() pour l'exécution parallèle :

// Bien : les opérations sont effectuées en parallèle (3 secondes)
async function loadData() {
  const [users, posts] = await Promise.all([
    fetchUsers(),
    fetchPosts()
  ]);
  return { users, posts };
}

Promise.allSettled()

Pour les cas où les résultats de toutes les opérations sont nécessaires :

async function loadAllData() {
  const results = await Promise.allSettled([
    fetchUsers(),
    fetchPosts(),
    fetchComments()
  ]);
  
  results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      console.log(`Operation ${index} succeeded:`, result.value);
    } else {
      console.error(`Operation ${index} failed:`, result.reason);
    }
  });
}

Promise.race()

Pour les opérations avec délai d'attente :

async function fetchWithTimeout(url, timeout = 5000) {
  const timeoutPromise = new Promise((_, reject) => 
    setTimeout(() => reject(new Error('Request timeout')), timeout)
  );
  
  return Promise.race([
    fetch(url),
    timeoutPromise
  ]);
}

Async/attendre dans les cycles

Soyez prudent avec les cycles — ils peuvent créer un comportement inattendu :

// Traitement séquentiel
async function processSequentially(items) {
  for (const item of items) {
    await processItem(item); // Nous attendons la fin de chaque opération
  }
}

// Traitement parallèle
async function processInParallel(items) {
  await Promise.all(items.map(item => processItem(item)));
}

// Traitement par lots
async function processBatches(items, batchSize = 5) {
  for (let i = 0; i < items.length; i += batchSize) {
    const batch = items.slice(i, i + batchSize);
    await Promise.all(batch.map(item => processItem(item)));
  }
}

Erreurs courantes

1. Await oublié

// Erreur : la fonction renvoie une promesse, pas des données
async function getData() {
  return fetchData(); // Vous avez oublié await
}

// Correct
async function getData() {
  return await fetchData();
}

2. Utilisation de await dans forEach

// Ne fonctionne pas : forEach ne comprend pas async
items.forEach(async (item) => {
  await processItem(item);
});

// Utilisez for...of
for (const item of items) {
  await processItem(item);
}

3. Création de promesses dans le cycle sans contrôle

// Créera des milliers de requêtes simultanées
const promises = items.map(item => fetchItem(item));
await Promise.all(promises);

// Il est préférable de contrôler le parallélisme

Motifs avancés

Retry avec un délai exponentiel :

async function fetchWithRetry(url, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fetch(url);
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      const delay = Math.pow(2, i) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

Mise en cache des résultats :

const cache = new Map();

async function fetchWithCache(key, fetcher) {
  if (cache.has(key)) {
    return cache.get(key);
  }
  const result = await fetcher();
  cache.set(key, result);
  return result;
}

Debounce pour les fonctions asynchrones :

function asyncDebounce(func, wait) {
  let timeout;
  return function(...args) {
    return new Promise((resolve) => {
      clearTimeout(timeout);
      timeout = setTimeout(async () => {
        resolve(await func.apply(this, args));
      }, wait);
    });
  };
}

Async/await dans d'autres langages

Le concept d'async/await n'existe pas seulement en JavaScript :

Python:

async def fetch_data():
    response = await aiohttp.get('https://api.example.com')
    return await response.json()

C#:

async Task<string> FetchDataAsync() {
    var response = await httpClient.GetAsync("https://api.example.com");
    return await response.Content.ReadAsStringAsync();
}

Rust:

async fn fetch_data() -> Result<String, Error> {
    let response = reqwest::get("https://api.example.com").await?;
    Ok(response.text().await?)
}

Performance et meilleures pratiques

1. Évitez les attentes inutiles

// Non optimal
async function process() {
  const result = await computeValue();
  return result; // Await superflu
}

// Mieux
async function process() {
  return computeValue();
}

2. Utilisez le parallélisme lorsque cela est possible

// Lentement
const user = await getUser();
const posts = await getPosts();

// Plus rapide
const [user, posts] = await Promise.all([getUser(), getPosts()]);

3. Ajoutez des délais d'attente pour les requêtes externes

async function safeFetch(url) {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), 5000);
  
  try {
    const response = await fetch(url, { signal: controller.signal });
    return response;
  } finally {
    clearTimeout(timeout);
  }
}

Conclusion

Async/await rend le code asynchrone lisible et compréhensible, éliminant les problèmes de callback hell et simplifiant le traitement des erreurs. Points clés :

  • Utilisez async/await pour les opérations séquentielles

  • Utilisez Promise.all() pour l'exécution parallèle

  • N'oubliez pas de traiter les erreurs via try-catch

  • Soyez prudent avec les cycles et utilisez toujours await là où vous en avez besoin

  • Contrôlez le parallélisme pour éviter de surcharger le système

La pratique et la compréhension du moment où les opérations doivent être effectuées de manière séquentielle et du moment où elles doivent être effectuées en parallèle vous aideront à écrire un code asynchrone efficace.

Code propose des cours structurés en JavaScript, Python, C, Rust et de nombreux autres langages, où vous pouvez apprendre la programmation asynchrone des bases aux modèles avancés. Des leçons interactives avec des exercices pratiques vous aideront à consolider vos connaissances sur des exemples réels.

Vous avez des questions sur async/await ou vous êtes confronté à une tâche difficile ? Rejoignez notre chaîne Telegram, où des développeurs expérimentés et une communauté active sont toujours prêts à vous aider à résoudre n'importe quel problème, des subtilités syntaxiques aux solutions architecturales. Posez des questions, partagez vos expériences et apprenez avec la communauté !

🎯Arrête de reporter

Tu as aimé l'article ?
Place à la pratique !

Avec Kodik, tu ne lis pas seulement — tu codes immédiatement. Théorie + pratique = vraies compétences.

Pratique instantanée
🧠L'IA explique le code
🏆Certificat

Sans inscription • Sans carte