Maison >interface Web >js tutoriel >Tout ce que vous devez savoir sur les promesses JavaScript et leur fonctionnement

Tout ce que vous devez savoir sur les promesses JavaScript et leur fonctionnement

Patricia Arquette
Patricia Arquetteoriginal
2024-12-17 03:33:25717parcourir

Everything You Need to Know About JavaScript Promises and How They Work

Le développement Web moderne s'appuie fortement sur des activités asynchrones pour permettre des applications réactives et interactives. Qu’il s’agisse de récupérer des données depuis une API, de lire des fichiers ou d’exécuter des timers, ces processus doivent s’exécuter en arrière-plan sans figer l’interface. JavaScript vous offre un moyen fiable de gérer ces tâches. Cet article couvre tout ce que vous devez savoir sur les promesses, y compris les idées de base et les fonctionnalités avancées, pour développer des programmes asynchrones sans erreur.

Dans cet article, vous découvrirez —

  • Qu'est-ce qu'une promesse ?

  • Pourquoi utiliser les promesses ?

  • Comment fonctionnent les promesses ?

  • Gérer les promesses

  • Enchaîner les promesses

  • Gestion des erreurs dans les promesses

  • Fonctionnalités avancées de la promesse

  • Flux d'exécution JavaScript avec promesses (important)

  • Conversion des chaînes de promesses en Async/Await

  • Meilleures pratiques et erreurs courantes

Qu'est-ce qu'une promesse ?

Une promesse en JavaScript équivaut à faire une « promesse » de faire quelque chose dans le futur. Lorsque vous faites une promesse, vous dites : « Je promets de vous donner les résultats plus tard ». Ce résultat pourrait être un succès ou un échec.

En d'autres termes, une promesse est un objet qui reflète le succès (ou l'échec) ultime d'une opération asynchrone et la valeur qui en résulte. Il vous permet de corréler les gestionnaires avec le succès ou l'échec d'une action asynchrone, rendant votre code plus facile à lire et à maintenir.

Pourquoi utiliser les promesses ?

En JavaScript, par exemple, les opérations fastidieuses, comme la récupération de données à partir d'un serveur, étaient généralement réalisées avec des rappels. Un rappel est simplement une fonction transmise à une autre fonction à exécuter une fois la tâche terminée. Vous pouvez utiliser un rappel, par exemple, pour traiter les données lorsqu'elles arrivent d'un serveur.

Cependant, lorsqu'il y a des opérations complexes, l'utilisation des rappels devient assez compliquée. Ce désordre est connu sous le nom de « l'enfer des rappels », où l'on peut avoir un rappel dans un autre, ce qui rend le code illisible et ingérable.

Exemple de rappel :

    fetchData((data) => {
      processData(data, (processedData) => {
        saveData(processedData, (result) => {
          console.log(result);
        });
      });
    });

Comme indiqué ci-dessus, un tel code devient de plus en plus difficile à lire et à maintenir dans des bases de code plus volumineuses en raison de sa structure profondément imbriquée, souvent appelée « l'enfer des rappels ».

Des promesses ont été introduites pour résoudre ce problème, offrant une manière plus propre et plus organisée de gérer les tâches asynchrones en permettant le chaînage de manière plus lisible.

Approche basée sur les promesses :

    fetchData((data) => {
      processData(data, (processedData) => {
        saveData(processedData, (result) => {
          console.log(result);
        });
      });
    });

Cette approche aplatit la structure et rend le code plus lisible et maintenable.

Comment fonctionnent les promesses ?

Les promesses en JavaScript peuvent être dans l'un des trois états suivants :

  1. En attente : Il s'agit de la première étape. La promesse n’a pas encore été tenue.

  2. Réalisée : La promesse s'est terminée avec succès, ce qui signifie qu'elle est résolue et a une valeur.

  3. Rejeté : la promesse n'a pas abouti et elle comporte un message d'erreur.

Syntaxe de base

fetchData()
  .then(processData)
  .then(saveData)
  .then(console.log)
  .catch(console.error);

Dans cet exemple, la promesse se résout après 1 seconde avec le message « Promesse résolue ! ». La méthode.then() est utilisée pour gérer la valeur résolue.

Gérer les promesses

Utilisation de .then() pour la gestion du succès

La méthode.then() est utilisée pour gérer ce qui se passe lorsqu'une promesse est terminée avec succès. Il enregistre les fonctions (rappels) à exécuter lorsque la promesse est remplie.

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Promise resolved!");
  }, 1000);
});

myPromise.then(result => console.log(result));

Utilisation de .catch() pour la gestion des erreurs

La méthode.catch() est utilisée pour gérer ce qui se passe lorsqu'une promesse échoue. Il enregistre une fonction (rappel) à exécuter lorsque la promesse est rejetée.

myPromise.then(data => {
  console.log("Data received:", data);
});

Utilisation de .finally() pour le nettoyage

La méthode.finally() vous permet d'exécuter du code une fois la promesse faite, qu'elle ait réussi ou non.

myPromise.catch(error => {
  console.error("Error:", error);
});

Enchaîner les promesses

Le chaînage permet d'effectuer des tâches de manière séquentielle en transmettant le résultat de la précédente. Passez ensuite au next.then(). Cela vous permet de gérer plusieurs tâches asynchrones de manière séquentielle.

Exemple de chaînage :

myPromise.finally(() => {
  console.log("Cleanup tasks");
});

Cet exemple utilise each.then() pour gérer chaque étape du processus, permettant un flux de données clair. Cela vous permet de voir comment le résultat d'une étape est transféré à la suivante.

Gestion des erreurs dans les promesses

Les promesses simplifient la gestion des erreurs en leur permettant de transmettre la chaîne à la méthode.catch() pour la résolution. Cela élimine le besoin de gérer les échecs à chaque phase, gardant votre code plus clair et plus facile à gérer.

Exemple avec propagation d'erreur :

fetch('https://api.example.com/user')
  .then(response => response.json())
  .then(data => {
    console.log("Processed data:", data);
    return processData(data);
  })
  .then(finalResult => {
    console.log("Final result:", finalResult);
  })
  .catch(error => console.error("Error:", error));

Si une étape de la chaîne de promesse échoue, l'erreur sera détectée par le bloc.catch(). Cela facilite la gestion des problèmes et garantit le bon fonctionnement de votre code.

Fonctionnalités avancées de la promesse

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

La méthode Promise.all() vous permet d'exécuter plusieurs promesses simultanément et d'attendre qu'elles se terminent toutes. Si toutes les promesses sont tenues, vous recevrez les résultats de chacune. Si une promesse échoue, il détecte l'erreur.

fetchData()
  .then(processData)
  .then(saveData)
  .catch(error => console.error("An error occurred:", error));

Dans cet exemple, si une promesse échoue, l'intégralité de Promise.all() échoue.

2. Promise.race() pour la promesse la plus rapide

La méthode Promise.race() renvoie le résultat de la première promesse qui se termine, qu'elle réussisse ou échoue.

    fetchData((data) => {
      processData(data, (processedData) => {
        saveData(processedData, (result) => {
          console.log(result);
        });
      });
    });

Dans cet exemple, quelle que soit la promesse (fetchData1 ou fetchData2) terminée en premier, son résultat sera enregistré dans la console.

3. Promise.allSettled() pour gérer tous les résultats

La méthode Promise.allSettled() attend que toutes les promesses que vous lui donnez soient dans un état de réussite ou d'échec, puis se termine. Un tableau est ensuite renvoyé contenant les résultats de chaque promesse.

fetchData()
  .then(processData)
  .then(saveData)
  .then(console.log)
  .catch(console.error);

Dans cet exemple, Promise.allSettled() attend la fin de fetchData1() et fetchData2(). Il enregistre ensuite le statut et le résultat (ou l'erreur) de chaque promesse. De cette façon, vous pouvez voir ce qui s'est passé avec chaque promesse, qu'elle ait réussi ou échoué.

4.Promise.any() pour résoudre avec la première promesse réussie

La méthode Promise.any() attend que la première promesse soit résolue correctement à partir d'une liste de promesses. Dans le cas où au moins une promesse est résolue, la valeur sera renvoyée par la méthode Promise.any(). Si toutes les promesses sont refusées, cette méthode générera une erreur.

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Promise resolved!");
  }, 1000);
});

myPromise.then(result => console.log(result));

Dans cet exemple, Promise.any() attend que la première promesse soit résolue avec succès. La procédure renvoie le résultat de la première promesse réussie, dans ce cas promesse2 avec la valeur « Succès A ». Si toutes les promesses sont refusées, le bloc.catch() est exécuté, enregistrant le message d'erreur. Cette stratégie est bénéfique lorsque l'on souhaite recevoir le résultat de la première promesse réussie sans avoir à attendre la suite.

Flux d'exécution JavaScript avec promesses (important)

1. Les promesses en JavaScript s'exécutent dans la file d'attente des microtâches, qui a la priorité sur les macrotâches comme setTimeout.

Voici un exemple pour illustrer cela :

myPromise.then(data => {
  console.log("Data received:", data);
});

Dans cet exemple :

  • console.log(2) s'exécute en premier car il s'agit d'une opération synchrone régulière.

  • console.log (6) s'exécute ensuite car il est également synchrone.

  • Le promise's.then() s'exécute avant le rappel setTimeout car les promesses sont des microtâches, qui ont une priorité plus élevée, donc imprime 3.

  • Enfin, le rappel setTimeout s'exécute, car il s'agit d'une macrotâche et imprime 4.

Alors rappelez-vous toujours que promise’s.then() s’exécute avant le rappel setTimeout en raison de la priorité de la file d’attente des microtâches.

2. Ordre d'exécution de promesse et file d'attente de microtâches avec plusieurs appels .then()

En JavaScript, le code s'exécute dans un ordre spécifique : d'abord le code synchrone, puis les microtâches (comme les promesses) et enfin les macrotâches (likesetTimeout).

Voici un exemple pour expliquer cela :

    fetchData((data) => {
      processData(data, (processedData) => {
        saveData(processedData, (result) => {
          console.log(result);
        });
      });
    });

Dans cet exemple, le code synchrone s'exécute en premier, en enregistrant 3, 6, 2, 7 et 8. Une fois le code synchrone terminé, les microtâches (les rappels.then()) sont traitées, en enregistrant 1 et 9. Enfin, les macrotâches (à partir de setTimeout) s'exécutent dans l'ordre de leurs délais, en enregistrant 21 (0 ms) et 13 (10 ms). Cela met en évidence l'ordre d'exécution de JavaScript : code synchrone > microtâches > macrotâches.

3. Plusieurs appels de résolution et de rejet dans une promesse : seul le premier compte

Lorsque vous créez une promesse, le premier appel à résoudre ou à rejeter est le seul qui compte. Tous les autres appels sont rejetés.

Voici un exemple pour illustrer cela :

fetchData()
  .then(processData)
  .then(saveData)
  .then(console.log)
  .catch(console.error);

Dans cet exemple, la promesse est résolue avec la valeur 1. La deuxième résolution et les appels de rejet sont ignorés car la promesse a déjà été réglée avec la première résolution.

4. Chaînage des promesses et gestion des valeurs dans les appels séquentiels .then()

Lorsque vous enchaînez des promesses, each.then() gère une étape du processus.

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Promise resolved!");
  }, 1000);
});

myPromise.then(result => console.log(result));

Dans cet exemple, Promise.resolve(1) commence avec une valeur de 1, mais le premier .then(() => 2) renvoie 2 à la place. Le prochain .then(3) est ignoré et la valeur 2 est transmise. Le .then((value) => value * 3) multiplie la valeur par 3, ce qui donne 6. Le .then(Promise.resolve(4)) ne change pas la valeur, et enfin, .then(console. log) logs 6. Cela montre comment les valeurs sont transmises à travers la chaîne, les valeurs non fonctionnelles étant ignorées.

5. Chaîne de promesses avec gestion de .catch() et .finally()

myPromise.then(data => {
  console.log("Data received:", data);
});

Dans cet exemple, nous enchaînons plusieurs méthodes.then(),.catch() et.finally() pour montrer comment les différentes étapes de résolution de promesse sont gérées. Décomposons-le :

  • finally() ne reçoit pas d'argument :
    Le bloc enfin() exécute le code de nettoyage mais ne prend ni ne transmet aucune valeur. Il est utilisé pour garantir que certains codes s’exécutent quel que soit le résultat de la promesse.

  • Renvoyer une valeur dansfinal() n'affecte pas la promesse :
    Si vous renvoyez une valeur dans le bloc enfin(), cela n'affecte pas la chaîne de promesse ni la valeur finale. Il est exécuté après la résolution/rejet de la promesse mais ne modifie pas le résultat.

  • Lancer une erreur dansfinal() provoque le rejet :
    Si vous lancez une erreur ou renvoyez une promesse rejetée dansfinal(), la chaîne de promesses sera rejetée avec l'erreur ou le motif du rejet.

myPromise.catch(error => {
  console.error("Error:", error);
});

OU

myPromise.finally(() => {
  console.log("Cleanup tasks");
});
  • L'ordre de then() et catch() compte Les .then() et .catch() peuvent être invoqués dans n’importe quel ordre, mais ils renverront toujours l’état final de la promesse. Lorsqu'une promesse est gérée par .catch(), tout .then() suivant recevra la valeur finale.

Exemple :

    fetchData((data) => {
      processData(data, (processedData) => {
        saveData(processedData, (result) => {
          console.log(result);
        });
      });
    });

Conversion des chaînes de promesses en Async/Await

Async/await est une méthode d'utilisation de promesses qui fait que le code ressemble davantage au code écrit en mode synchrone. Le terme souvent utilisé est « sucre syntaxique » car il donne un chemin plus simple et plus propre pour créer du code asynchrone.

fetchData()
  .then(processData)
  .then(saveData)
  .then(console.log)
  .catch(console.error);

Combiner des promesses avec Async/Await

Vous pouvez combiner des promesses avec async/await pour une exécution parallèle en utilisant Promise.all().

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Promise resolved!");
  }, 1000);
});

myPromise.then(result => console.log(result));

Meilleures pratiques et erreurs courantes

  • Évitez l'imbrication profonde : Utilisez le chaînage ou l'async/wait pour garder le code plat et lisible.

  • Toujours gérer les erreurs : Assurez-vous que chaque chaîne de promesses a un.catch() ou un bloc try/catch.

  • Utilisez judicieusement l'exécution parallèle : Utilisez Promise.all() uniquement lorsque les tâches sont indépendantes mais doivent se terminer ensemble.

Conclusion

Les promesses JavaScript sont l'un des meilleurs moyens de gérer vos opérations chronophages, telles que la récupération de données sur un serveur. Ils vous aident même à écrire un code plus propre et plus facile à maintenir, et la pratique de ce que vous avez appris vous permettra de tirer pleinement parti du codage asynchrone. Une fois que vous aurez acquis une certaine expérience pratique et commencé à gérer les erreurs avec élégance, les promesses deviendront une partie importante de JavaScript.

Merci d'avoir lu ! Si vous trouvez cet article utile, n'hésitez pas à le souligner, à applaudir, à laisser un commentaire ou même à me contacter sur Twitter/X et LinkedIn car il est très apprécié et aide à garder un contenu comme celui-ci gratuit !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn