JavaScript asynchrone

Découvre comment JavaScript gère les opérations qui prennent du temps sans figer la page. Suis le fonctionnement de la boucle d’événements pour prévoir l’ordre d’exécution du code, planifie des opérations avec des minuteries et écris du code asynchrone sous ses trois formes : fonctions de rappel, promesses et fonctions asynchrones avec await. Gère les échecs avec catch, try et finally, et exécute des tâches indépendantes en même temps avec Promise.all et les autres combinateurs de promesses.

DébutantUnité 7 sur 9 de la formation Formation : JavaScript : DOM, événements et code asynchrone

Ce que tu vas apprendre

  1. Distingue le code synchrone du code asynchrone, suis le fonctionnement de la boucle d’événements avec la pile d’appels et ses files, et planifie des opérations avec des minuteries.
    • Distingue le code synchrone du code asynchrone
      Explique pourquoi JavaScript exécute une seule partie de ton code à la fois, pourquoi un code long à exécuter fige une page et comment les opérations asynchrones permettent à un programme de continuer à travailler pendant l’attente.
    • Suis le fonctionnement de la boucle d’événements
      Suis le rôle de la pile d’appels, de la file de tâches et de la file de microtâches dans l’ordre d’exécution du code, et prévois les résultats d’un code qui combine minuteries et promesses.
    • Planifie l’exécution de code avec des minuteries
      Exécute du code une fois après un délai ou à plusieurs reprises avec setTimeout et setInterval, annule des minuteries et explique pourquoi leur délai est une attente minimale plutôt qu’une durée exacte.
  2. Passe des fonctions à des opérations asynchrones, transmets les erreurs selon la convention de l’erreur en premier et comprends pourquoi les fonctions de rappel profondément imbriquées sont difficiles à lire et à maintenir.
    • Passe des fonctions de rappel à des opérations asynchrones
      Écris des fonctions qui acceptent une fonction de rappel, distingue les fonctions de rappel synchrones des fonctions asynchrones et transmets un résultat asynchrone au code qui en a besoin.
    • Gère les erreurs dans les fonctions de rappel et évite l’enfer des fonctions de rappel
      Utilise la convention de la fonction de rappel avec erreur en premier, explique pourquoi try et catch ne peuvent pas intercepter une erreur levée plus tard dans une fonction de rappel, et réduis l’imbrication du code utilisant des fonctions de rappel.
  3. Crée des promesses, réagis à leurs résultats avec then, catch et finally, et enchaîne des étapes asynchrones dans une séquence lisible.
    • Explique les états d’une promesse et crée une promesse
      Décris les états possibles d’une promesse, crée des promesses avec le constructeur Promise et encapsule une minuterie dans une promesse.
    • Réagis aux résultats des promesses avec then, catch et finally
      Enregistre des gestionnaires qui s’exécutent lorsqu’une promesse est tenue, rejetée ou acquittée, et utilise-les pour mettre une page à jour au bon moment.
    • Enchaîne des promesses
      Renvoie des valeurs et des promesses depuis les gestionnaires pour construire des chaînes sans imbrication d’étapes dépendantes, et évite les erreurs d’oubli de return et d’imbrication.
  4. Écris des fonctions asynchrones, suspends-les avec await jusqu’à l’acquittement des promesses, réécris des chaînes de promesses et des API à fonctions de rappel sous cette forme, et évite les erreurs courantes du code asynchrone.
    • Écris des fonctions asynchrones et utilise await
      Déclare des fonctions asynchrones, explique ce qu’elles renvoient et utilise await pour suspendre une fonction jusqu’à l’acquittement d’une promesse sans bloquer la page.
    • Réécris des chaînes de promesses et des API à fonctions de rappel avec async et await
      Transforme des chaînes de promesses en fonctions asynchrones, encapsule des fonctions utilisant des fonctions de rappel dans des promesses pour pouvoir les attendre, et choisis un style clair.
    • Évite les erreurs courantes avec async et await
      Repère et corrige les oublis de await, les fonctions de rappel asynchrones dans forEach, les promesses utilisées comme conditions et les appels asynchrones dont les erreurs ne sont pas gérées.
  5. Intercepte les échecs et prévois une récupération dans les chaînes de promesses et avec try et catch, effectue le nettoyage avec finally et assure-toi qu’aucun échec ne passe inaperçu.
    • Gère les rejets dans les chaînes de promesses
      Suis la propagation d’un rejet dans une chaîne de promesses, récupère après l’erreur ou transmets-la, et place les gestionnaires catch là où ils traiteront les échecs concernés.
    • Utilise try, catch et finally avec await
      Utilise les objets Error et l’instruction try, catch et finally pour gérer les échecs des promesses attendues, effectuer le nettoyage de façon fiable et proposer des solutions de repli utiles.
    • Rends les échecs visibles et prévois une récupération adaptée
      Évite les rejets non gérés et les erreurs passées sous silence, ajoute du contexte aux erreurs et choisis entre une nouvelle tentative, une solution de repli et une information à l’utilisateur.
  6. Lance des tâches indépendantes en même temps, attends leurs résultats ensemble et choisis le combinateur de promesses adapté aux situations où il faut tout ou rien, obtenir les résultats disponibles, attendre la première tâche terminée ou la première réussite.
    • Lance des tâches ensemble et attends leurs résultats avec Promise.all
      Exécute des tâches asynchrones indépendantes en même temps, combine leurs résultats avec Promise.all et explique les délais et le comportement en cas d’échec.
    • Choisis entre Promise.allSettled, Promise.race et Promise.any
      Utilise allSettled lorsque chaque issue compte, race pour la première tâche acquittée, par exemple pour un délai d’expiration, et any pour la première réussite ; compare les quatre combinateurs.

JavaScript asynchrone : cours

6 chapitres

1

Explique comment JavaScript exécute du code asynchrone

JavaScript doit souvent attendre qu’une personne clique ou qu’une minuterie arrive à son terme. Pendant cette attente, la page doit rester réactive. Représente-toi ce qui s’exécute maintenant, ce qui attend dans l’environnement et ce qui rejoint une file pour plus tard. Utilise ensuite cette représentation pour suivre les résultats dans la console et planifier des minuteries. L’essentiel est de suivre le moment où une fonction est appelée, et pas seulement l’endroit où son nom apparaît dans le code.

1.1 Distingue le code synchrone du code asynchrone

Le code synchrone termine l’instruction en cours avant de passer à la suivante. Le JavaScript de ta page s’exécute sur un seul thread principal : deux parties de ce code ne s’exécutent donc pas au même instant. C’est facile à suivre jusqu’à ce qu’une instruction lance une opération dont le résultat arrivera plus tard.

Commencer maintenant, traiter le résultat plus tard

Une opération asynchrone commence maintenant et transmet son résultat ensuite, par une fonction de rappel ou une promesse. Le navigateur ou Node.js est l’environnement hôte. Il gère l’attente pendant que ton programme continue. Les minuteries, les actions de l’utilisateur et le chargement d’images fonctionnent tous de cette façon.

console.log("Opening");
setTimeout(() => console.log("Ready"), 700);
console.log("Waiting");

Lis l’appel à setTimeout comme « enregistre cette fonction ». Il se termine sans attendre 700 ms. Le script en cours affiche donc d’abord « Opening » et « Waiting ». Après environ 700 ms, la fonction de rappel peut s’exécuter et afficher « Ready ». Le délai exact dépend aussi du moment où le thread principal se libère.

Il y a ici deux activités distinctes : l’environnement suit la minuterie et JavaScript finit par appeler la fonction qui affiche le résultat. L’attente se superpose à d’autres opérations ; la fonction de rappel s’exécute toujours sur le thread principal.

Pourquoi une page se fige

Une longue boucle synchrone occupe le thread. Pendant son exécution, les gestionnaires de clic et les fonctions de rappel des minuteries ne peuvent pas s’exécuter, et la page ne peut pas mettre son affichage à jour par ce thread. Enregistrer une minuterie avec un délai nul ne l’autorise pas à interrompre la boucle.

Supposons qu’une minuterie arrive à son terme pendant qu’un calcul est encore en cours. L’environnement place sa fonction de rappel dans une file. C’est la fin du calcul qui libère le thread ; l’expiration du délai de la minuterie ne peut pas le faire à elle seule. Une fonction de rappel qui effectue un autre long calcul peut aussi figer la page.

Pour réduire l’effet d’un calcul sur la réactivité, divise-le en petites parties qui laissent d’autres tâches s’exécuter entre elles, ou déplace les opérations qui s’y prêtent dans un Web Worker, un thread distinct en arrière-plan fourni par le navigateur. Placer simplement une grande boucle dans une fonction asynchrone laisse cette boucle sur le thread principal.

Trois façons de recevoir un résultat

Une fonction de rappel transmet l’action suivante sous forme de fonction. Une promesse représente une issue future et permet d’ajouter des gestionnaires de réussite et d’échec. Une fonction asynchrone utilise des promesses, tandis que await permet de suspendre son exécution à un endroit précis.

Ces formes coexistent. Une minuterie reçoit toujours une fonction de rappel, même lorsque le code qui l’entoure utilise des promesses. Une fonction asynchrone peut attendre une promesse produite par une fonction enveloppante utilisant une fonction de rappel. Choisis la forme qui permet de suivre facilement le parcours du résultat.

Lorsque tu lis du code asynchrone, repère d’abord les instructions qui s’exécutent pendant l’appel en cours. Repère ensuite les fonctions enregistrées pour plus tard. Une ligne située dans une fonction de rappel enregistrée ne s’exécute pas simplement parce que l’exécution a atteint la ligne qui crée cette fonction.

Points clés

  • Le JavaScript synchrone occupe le thread principal jusqu’à la fin du travail en cours.
  • L’environnement hôte gère l’attente et planifie le code qui traite le résultat.
  • Les fonctions de rappel asynchrones s’exécutent plus tard sur le thread principal.
  • Une fonction asynchrone peut toujours bloquer la page avec un long calcul.

1.2 Suis le fonctionnement de la boucle d’événements

La boucle d’événements coordonne les opérations prêtes à s’exécuter. Pour prévoir les résultats, distingue trois choses : les fonctions qui s’exécutent maintenant, les fonctions de rappel qui attendent comme tâches et les opérations liées aux promesses qui attendent comme microtâches.

Suivre la pile et les files

La pile d’appels contient les appels de fonctions actifs. Appeler une fonction y ajoute un cadre ; le retour de cette fonction retire le cadre. La fonction en cours s’exécute jusqu’à ce qu’elle se termine ou appelle une autre fonction.

Une tâche peut être un script, une fonction de rappel de minuterie ou un gestionnaire de clic. Les tâches s’exécutent une par une. Les navigateurs peuvent avoir plusieurs files de tâches : ne suppose donc pas que toutes les sources d’opérations partagent une seule file universelle où le premier arrivé est le premier servi.

La file de microtâches contient les gestionnaires de promesses de then, catch et finally, les continuations après await et les fonctions de rappel passées à queueMicrotask. À un point de contrôle des microtâches après le travail en cours, la file se vide avant la tâche suivante. Les microtâches ajoutées pendant ce traitement s’exécutent aussi avant la tâche suivante.

Suivre un script
console.log("begin");
setTimeout(() => console.log("timer"), 0);
Promise.resolve().then(() => console.log("promise"));
console.log("finish");
  1. Le script affiche « begin ».
  2. Il enregistre une fonction de rappel de minuterie ; il ne l’appelle pas.
  3. Il place le gestionnaire de la promesse tenue dans la file comme microtâche.
  4. Il affiche « finish » et termine le travail en cours.
  5. La microtâche affiche « promise ».
  6. La tâche de la minuterie affiche « timer ».

Une promesse déjà tenue planifie tout de même l’exécution de son gestionnaire pour plus tard. Un délai de 0 ms planifie tout de même une tâche de minuterie.

Inclure les opérations ajoutées en cours de route
Promise.resolve()
  .then(() => console.log("first"))
  .then(() => console.log("third"));
queueMicrotask(() => console.log("second"));
console.log("now");

Le script affiche « now ». La file de microtâches contient d’abord le premier gestionnaire de promesse, puis la fonction de rappel de queueMicrotask. Lorsque le premier gestionnaire affiche « first » et se termine, il rend le gestionnaire de promesse suivant prêt à s’exécuter. Ce nouveau gestionnaire rejoint la fin de la file. La suite des résultats est « second », puis « third ».

Achèvement et réactivité

Une fois qu’une tâche ou une microtâche commence, une opération ajoutée à une file de façon asynchrone ne peut pas l’interrompre. Ce fonctionnement d’exécution jusqu’à achèvement permet de raisonner sur une modification locale sans qu’une minuterie intervienne soudainement au milieu de la fonction.

Une fois les microtâches terminées, le navigateur peut mettre l’écran à jour lorsqu’une occasion de rendu se présente. Il n’a pas à redessiner la page après chaque tâche. Un flux infini de microtâches peut empêcher les tâches suivantes et le rendu : chaque nouvelle microtâche prolonge le traitement de la file en cours. Reporter une opération dans une microtâche ne garantit donc pas que la page aura l’occasion de réagir.

Pour suivre l’exécution, écris d’abord les résultats immédiats, traite les microtâches dans l’ordre jusqu’à vider leur file, puis passe aux tâches de minuterie prêtes. Ajoute les opérations nouvellement planifiées à la file appropriée au moment où le code les planifie effectivement.

Suivre une minuterie créée par une microtâche
setTimeout(() => console.log("outer timer"), 0);
Promise.resolve().then(() => {
  console.log("job one");
  setTimeout(() => console.log("inner timer"), 0);
}).then(() => console.log("job two"));
console.log("script");

Le script enregistre la minuterie externe et le premier gestionnaire de promesse, puis affiche « script ». La première microtâche affiche « job one » et enregistre la minuterie interne. Le retour de ce gestionnaire place « job two » dans la file ; cette microtâche s’exécute aussi avant toute tâche de minuterie. Les résultats se terminent par « outer timer », puis « inner timer » : les deux minuteries ont le même délai et la minuterie externe a été enregistrée en premier.

Créer une minuterie pendant une microtâche ne fait pas de sa fonction de rappel une microtâche. Classe l’opération selon l’API de planification qui la reçoit, puis ajoute-la à la file appropriée.

Points clés

  • La pile d’appels enregistre les appels actifs.
  • Les gestionnaires de promesses et les continuations après await s’exécutent comme des microtâches.
  • Traite les microtâches nouvellement ajoutées avant de prendre une autre tâche.
  • Les fonctions de rappel en attente ne peuvent pas interrompre le code JavaScript en cours d’exécution.
  • Le rendu est possible après les microtâches, mais il n’est pas garanti après chaque tâche.

1.3 Planifie l’exécution de code avec des minuteries

Les minuteries planifient l’exécution ultérieure de fonctions de rappel. Elles mesurent un délai en millisecondes : 1 000 ms correspondent à 1 s. Le délai détermine à partir de quand une fonction de rappel peut être exécutée ; d’autres opérations et les limites du navigateur peuvent retarder son exécution.

Planifier et annuler un appel
function remind(topic) {
  console.log("Review " + topic);
}
const reminder = setTimeout(remind, 2000, "promises");
// To cancel before it runs:
clearTimeout(reminder);

Les arguments supplémentaires placés après le délai sont transmis à la fonction de rappel. Un délai omis est considéré comme égal à 0. Conserve l’identifiant de minuterie renvoyé si tu peux avoir besoin de l’annuler. Les navigateurs renvoient un identifiant numérique ; Node.js renvoie un objet Timeout. Les deux fonctionnent avec clearTimeout. Annuler une minuterie terminée ou inexistante n’a aucun effet.

Passe une fonction : setTimeout(remind, 2000, "promises"). Écrire setTimeout(remind("promises"), 2000) appelle remind immédiatement et passe sa valeur de retour à la minuterie. Une fonction fléchée est une autre façon de différer un appel avec des arguments : setTimeout(() => remind("promises"), 2000).

Répéter avec une minuterie périodique ou une nouvelle temporisation
let ticks = 0;
const clock = setInterval(() => {
  ticks++;
  console.log("Tick " + ticks);
  if (ticks === 3) clearInterval(clock);
}, 1000);

La première exécution a lieu après environ une seconde. La troisième fonction de rappel arrête les exécutions suivantes. Conserve l’identifiant de la minuterie périodique et utilise clearInterval lorsque l’opération répétée doit prendre fin.

Une fonction de rappel peut aussi planifier sa propre prochaine temporisation. Lorsqu’elle appelle setTimeout à la fin de son travail synchrone, le délai suivant commence après ce travail. Cela crée une pause entre les exécutions et permet de modifier le délai à chaque fois. Une minuterie périodique continue de demander des exécutions à intervalles fixes ; une opération lente peut laisser peu de pause. Si une exécution lance une opération asynchrone, attends aussi la fin de celle-ci avant de planifier la prochaine exécution lorsque leur chevauchement poserait problème.

Les limites des délais

Un thread occupé retarde les fonctions de rappel prêtes à s’exécuter. Les navigateurs ralentissent aussi les minuteries dans les onglets en arrière-plan, souvent à environ une vérification par seconde ou moins. Lorsque le niveau d’imbrication des minuteries dépasse cinq, la règle HTML sur les minuteries porte les délais inférieurs à 4 ms à 4 ms. Les très grands délais demandent aussi de l’attention : la limite habituelle d’un entier signé sur 32 bits est 2147483647 ms, soit environ 24,8 jours ; les valeurs supérieures peuvent provoquer un dépassement et déclencher la minuterie bien plus tôt.

Capturer la bonne valeur de boucle
for (let i = 1; i <= 3; i++) {
  setTimeout(() => console.log(i), 100);
}

Chaque itération avec let possède sa propre liaison : la console affiche donc « 1 », « 2 », « 3 ». Avec var, toutes les fonctions de rappel partagent la même variable. Après la boucle, elle vaut 4 : chacune affiche donc « 4 ».

Attendre une période sans activité

L’anti-rebond annule une temporisation en attente chaque fois qu’un nouvel événement arrive. Une nouvelle temporisation planifie alors l’action après le dernier événement. Avec un délai de 300 ms, une frappe toutes les 100 ms continue de reporter l’action ; elle s’exécute environ 300 ms après la fin de la saisie. Stocke l’identifiant hors du gestionnaire pour que l’appel suivant puisse annuler la minuterie précédente.

Construire un gestionnaire avec anti-rebond
let pendingSave;
function scheduleSave(text) {
  clearTimeout(pendingSave);
  pendingSave = setTimeout(() => {
    console.log("Saved: " + text);
  }, 300);
}
scheduleSave("n");
scheduleSave("no");
scheduleSave("note");

Ces appels ont lieu dans le même script. Chacun annule la minuterie associée à l’identifiant précédent avant de le remplacer : seul « Saved: note » s’affiche donc, après environ 300 ms. La dernière fonction de rappel capture le paramètre de texte de cet appel. L’identifiant existe hors de la fonction afin que chaque appel puisse annuler la temporisation planifiée précédemment.

Si l’identifiant était déclaré à nouveau dans chaque appel, l’appel suivant ne conserverait pas l’identifiant de la minuterie précédente. Si un gestionnaire planifiait une temporisation sans annuler la précédente, il produirait les trois messages. L’anti-rebond a besoin à la fois de l’identifiant partagé et de l’annulation avant son remplacement.

Points clés

  • Passe une fonction de rappel et mesure les délais en millisecondes.
  • Utilise l’identifiant renvoyé pour annuler une minuterie.
  • Les délais des minuteries ne garantissent pas des instants d’exécution exacts.
  • Une minuterie périodique se répète jusqu’à son annulation.
  • Utilise let pour obtenir des liaisons de boucle distinctes.
  • L’anti-rebond redémarre un délai après chaque événement.
2

Écris et organise du code utilisant des fonctions de rappel

Une fonction de rappel permet au code appelant de fournir la prochaine opération sous forme de fonction. Cette idée simple est à la base des minuteries, des événements et de nombreuses API plus anciennes. Tu vas écrire une petite opération utilisant une fonction de rappel, suivre le résultat jusqu’au code qui en a besoin et transmettre les échecs par un paramètre d’erreur. Tu verras aussi comment des étapes dépendantes créent du code imbriqué et pourquoi une gestion cohérente des erreurs compte à chaque niveau.

2.1 Passe des fonctions de rappel à des opérations asynchrones

Une fonction de rappel est une fonction que tu passes à une autre fonction pour que celle-ci l’appelle. Le code de la fonction de rappel décrit ce qui doit être fait d’un résultat. Son exécution pendant l’appel en cours ou plus tard dépend de l’API qui la reçoit.

Une fonction de rappel peut s’exécuter de façon synchrone
const doubled = [2, 5].map(n => n * 2);
console.log(doubled);

map appelle sa fonction de rappel pour chaque élément avant de renvoyer le nouveau tableau. Le résultat est [4, 10]. La fonction fléchée est une fonction de rappel, mais ce code ne planifie aucune opération future. Tu peux utiliser doubled à la ligne suivante car le tableau est déjà complet.

Transmettre un résultat différé
function prepareLabel(name, callback) {
  setTimeout(() => {
    callback("Label: " + name);
  }, 200);
}
prepareLabel("Mira", label => {
  console.log(label);
});
console.log("Label requested");

prepareLabel lance une minuterie et se termine. Le script affiche « Label requested ». Après environ 200 ms, la fonction de rappel de la minuterie construit le libellé et appelle la fonction de rappel fournie, qui affiche « Label: Mira ». L’opération choisit quand appeler la fonction ; le code appelant choisit quoi faire du résultat.

Placer les opérations dépendantes là où le résultat existe
let label;
prepareLabel("Mira", value => {
  label = value;
});
console.log(label);

Ce code affiche undefined : l’affectation n’a pas encore eu lieu. Déplace console.log(value) dans la fonction de rappel. Ajouter une temporisation indépendante plus longue avant de lire label reviendrait seulement à deviner quand le résultat sera disponible ; utiliser la fonction de rappel du résultat lie l’opération à sa fin effective.

Un return dans une fonction de rappel différée ne peut pas non plus renvoyer la valeur depuis la fonction qui l’englobe. L’appel à cette dernière est déjà terminé. Dans l’exemple, return "Label: Mira" dans la fonction de rappel de la minuterie renverrait la valeur au mécanisme de la minuterie, laissant le code qui a appelé prepareLabel sans le libellé différé.

Passer l’action suivante sans l’appeler

Une fonction de rappel nommée fonctionne aussi :

function showLabel(label) {
  console.log(label);
}
prepareLabel("Mira", showLabel);

showLabel est la fonction elle-même. showLabel() l’appellerait immédiatement sans libellé et passerait sa valeur de retour à la place. Utilise une fonction fléchée enveloppante lorsque l’action ultérieure a besoin d’un argument particulier ou de plusieurs instructions.

Pour deux étapes asynchrones dépendantes, lance la seconde dans la fonction de rappel de la première. Par exemple, après avoir reçu un utilisateur, passe cet utilisateur à une opération qui prépare ses paramètres. Lancer les deux opérations en dehors de leurs fonctions de rappel n’établirait pas cette dépendance.

La fonction qui reçoit la fonction de rappel décide du nombre de fois où elle l’appelle. Certaines fonctions de rappel, comme les gestionnaires d’événements, sont volontairement appelées de nombreuses fois. Une opération qui produit un seul résultat doit appeler sa fonction de rappel de résultat une fois. Une promesse donne à une telle opération un résultat qui ne peut s’acquitter qu’une seule fois.

Points clés

  • Le moment où une fonction de rappel s’exécute dépend de l’API qui l’appelle.
  • map utilise des fonctions de rappel synchrones ; une fonction de rappel de minuterie s’exécute plus tard.
  • Utilise un résultat différé dans sa fonction de rappel ou dans du code appelé par celle-ci.
  • Le retour d’une fonction de rappel ne termine pas la fonction qui l’englobe.

2.2 Gère les erreurs dans les fonctions de rappel et évite l’enfer des fonctions de rappel

Une opération asynchrone peut aussi bien échouer que réussir. Une API à fonctions de rappel a besoin d’un moyen clair de transmettre chaque issue et d’un endroit précis où le code appelant peut la traiter.

Vérifier d’abord l’erreur

La convention de l’erreur en premier utilise callback(err, result). Un appel réussi passe null pour l’erreur. Un appel échoué passe un objet Error et ne fournit pas de résultat utilisable.

function readLabel(id, callback) {
  setTimeout(() => {
    if (id <= 0) {
      callback(new Error("Invalid label id"));
      return;
    }
    callback(null, { id: id, text: "Draft" });
  }, 200);
}
readLabel(4, (err, label) => {
  if (err) {
    console.log(err.message);
    return;
  }
  console.log(label.text);
});

Le code qui produit le résultat s’arrête après avoir signalé un identifiant non valide : il ne peut donc pas aussi signaler une réussite. Le code qui consomme le résultat s’arrête après avoir constaté une erreur : il ne peut donc pas essayer de lire label.text dans un résultat absent. Avec l’identifiant 4, la console affiche « Draft ». Avec l’identifiant 0, elle affiche « Invalid label id ».

Les deux retours sont importants. Sans le retour du code qui consomme le résultat, une seconde erreur concernant une valeur non définie pourrait masquer le message initial utile. Sans le retour du code qui produit le résultat, une opération pourrait appeler deux fois la fonction de rappel. Pour une API qui produit un seul résultat, signale exactement une issue.

Le bloc try autour de l’appel est déjà terminé
try {
  setTimeout(() => {
    throw new Error("Late failure");
  }, 0);
} catch (err) {
  console.log("Handled");
}

Le try planifie la minuterie et se termine. La fonction de rappel lève une exception dans une tâche ultérieure, lorsque ce try n’est plus actif : « Handled » ne s’affiche donc pas. Intercepte une éventuelle exception dans la fonction de rappel ou transmets l’échec par le paramètre d’erreur de l’API. Une fonction enveloppante renvoyant une promesse devra ensuite convertir explicitement cette erreur de fonction de rappel en rejet.

Garder les étapes dépendantes lisibles

Le code utilisant des fonctions de rappel devient difficile à suivre lorsque chaque étape suivante apparaît dans la fonction de rappel de l’étape précédente. Lire un profil, puis ses projets, puis les tâches d’un projet crée plusieurs niveaux d’imbrication. Chaque opération a aussi besoin de sa propre vérification d’erreur. Ce schéma est souvent appelé enfer des fonctions de rappel ou pyramide de malheur.

Des fonctions nommées peuvent donner à ces étapes des noms qui ont un sens et réduire l’imbrication visible. Garde une transmission des erreurs cohérente entre elles : une étape ultérieure peut échouer tout autant que la première. Les promesses et les fonctions asynchrones offrent une façon moins imbriquée d’exprimer la même séquence tout en maintenant la propagation des échecs.

Toutes les API à fonctions de rappel n’utilisent pas un paramètre d’erreur. Certains objets du navigateur disposent d’événements distincts pour la réussite et l’échec. Pour une image, définis les gestionnaires onload et onerror avant d’affecter une valeur à src, afin que les deux issues aient un gestionnaire au début du chargement. Lis le contrat de l’API avant de supposer qu’un paramètre nommé err existe.

Points clés

  • Une fonction de rappel avec erreur en premier reçoit err avant le résultat.
  • Termine la fonction après avoir signalé ou traité une erreur.
  • Les opérations qui produisent un seul résultat doivent appeler leur fonction de rappel exactement une fois.
  • Un try externe ne peut pas intercepter une exception levée plus tard par une fonction de rappel.
  • Des étapes nommées ou du code utilisant des promesses réduisent les imbrications profondes.
3

Crée et utilise des promesses

Une promesse donne à une opération un objet partagé pour son résultat futur. Elle rend explicites la réussite et l’échec et permet de relier des étapes dépendantes sans imbriquer chacune dans la précédente. Commence par construire une promesse autour d’une minuterie. Ajoute ensuite des gestionnaires, suis les nouvelles promesses qu’ils renvoient et vérifie que chaque étape asynchrone reste reliée à la chaîne qui en dépend.

3.1 Explique les états d’une promesse et crée une promesse

Une promesse représente une issue future. Une fonction peut la renvoyer immédiatement, ce qui permet au code appelant de relier des opérations à un résultat qui n’existe pas encore.

États et acquittement

Une promesse est en attente jusqu’à ce qu’elle soit tenue avec une valeur ou rejetée avec une raison. Les promesses tenues et rejetées sont acquittées ; leur issue ne peut plus changer.

« Résolue » a un sens plus précis que celui d’un synonyme courant de « réussie ». Une promesse résolue avec une autre promesse en attente suit l’issue future de cette dernière, y compris son éventuel rejet. Elle peut donc être résolue tout en étant encore en attente.

Créer une promesse autour d’une opération
function wait(ms) {
  return new Promise(resolve => {
    setTimeout(resolve, ms);
  });
}
wait(200).then(() => console.log("Pause finished"));

new Promise appelle immédiatement sa fonction exécutrice. Celle-ci enregistre une minuterie. Lorsque la minuterie appelle resolve, la promesse est tenue avec undefined et le gestionnaire then enregistré s’exécute plus tard comme microtâche. Cette fonction utilitaire fournit une pause réutilisable sans bloquer le thread.

Une fonction exécutrice peut recevoir à la fois resolve et reject :

function reserve(quantity) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (quantity <= 8) resolve(8 - quantity);
      else reject(new Error("Not enough stock"));
    }, 200);
  });
}
reserve(3).then(left => console.log(left));
reserve(9).catch(err => console.log(err.message));

Pour ces quantités positives, le premier appel est tenu avec 5 et le second est rejeté avec « Not enough stock ». La promesse permet au code appelant de recevoir l’une ou l’autre issue par le même objet renvoyé.

La création lance la fonction exécutrice
console.log("before");
const result = new Promise(resolve => {
  console.log("creating");
  resolve(12);
});
console.log("after");
result.then(value => console.log(value));

La console affiche « before », « creating », « after », « 12 ». Ajouter then ne lance pas cette fonction exécutrice. Le constructeur l’a déjà exécutée ; then enregistre le code qui utilisera son résultat.

Seul le premier appel à resolve ou reject détermine le sort de la promesse. Les appels suivants ne peuvent pas le modifier. Cela s’applique aussi lorsque la première résolution adopte une autre promesse dont le résultat est encore en attente. Appeler resolve n’arrête pas le code ordinaire de la fonction exécutrice : utilise donc return lorsqu’une branche doit se terminer.

Faire en sorte que chaque chemin se termine correctement

Une exception levée de façon synchrone dans la fonction exécutrice rejette automatiquement la promesse. Une exception levée plus tard dans une fonction de rappel de minuterie se produit en dehors de cet appel et n’est pas convertie en rejet. Utilise reject(new Error("...")) à cet endroit ; sinon, l’erreur peut ne pas être interceptée tandis que la promesse reste en attente.

Une branche qui n’appelle aucune des deux fonctions peut laisser le code appelant attendre indéfiniment. Utilise des objets Error comme raisons de rejet afin que les gestionnaires puissent lire un message et que les outils de débogage puissent afficher des informations utiles sur l’erreur.

Promise.resolve(value) crée une promesse tenue pour une valeur ordinaire ou adopte l’issue d’une autre promesse. Promise.reject(error) crée une promesse rejetée. Ajoute un gestionnaire de rejet lorsque tu utilises cette dernière.

Suivre une issue adoptée
const inner = new Promise(resolve => {
  setTimeout(() => resolve("packed"), 250);
});
const outer = new Promise((resolve, reject) => {
  resolve(inner);
  reject(new Error("Too late to replace it"));
});
outer.then(value => console.log(value));

La fonction exécutrice interne lance sa minuterie pendant la construction. La fonction exécutrice externe se résout ensuite avec inner, ce qui lie définitivement outer à l’issue future de inner. L’appel ultérieur à reject ne peut pas modifier cette décision. Outer reste en attente jusqu’à ce que inner soit tenue, puis son gestionnaire affiche « packed » après environ 250 ms.

Si inner était rejetée, outer suivrait ce rejet. Le premier appel à resolve a choisi l’issue à suivre ; il n’a pas garanti une réussite. Cette distinction compte lorsqu’une fonction enveloppante transmet une autre promesse au lieu de fournir une valeur ordinaire déjà disponible.

Points clés

  • Les promesses en attente deviennent tenues ou rejetées ; une fois acquittées, leur issue reste fixe.
  • La résolution peut adopter l’issue future d’une autre promesse.
  • La fonction exécutrice s’exécute de façon synchrone pendant la construction.
  • Utilise resolve et reject pour relier les fonctions de rappel ultérieures à la promesse.
  • Une exception levée plus tard dans une fonction de rappel ne rejette pas automatiquement la promesse qui l’englobe.

3.2 Réagis aux résultats des promesses avec then, catch et finally

Les gestionnaires de promesses relient du code à une réussite, à un échec ou aux deux issues possibles. Chaque enregistrement d’un gestionnaire renvoie aussi une nouvelle promesse, ce qui permet au code suivant de recevoir ce que produit ce gestionnaire.

Utiliser le gestionnaire adapté à l’issue

p.then(onFulfilled) reçoit la valeur d’une promesse tenue. p.catch(onRejected) reçoit la raison d’un rejet ; c’est une forme abrégée de p.then(undefined, onRejected). Les gestionnaires sont des fonctions et s’exécutent comme des microtâches, même si p est déjà acquittée.

Promise.resolve("draft")
  .then(text => console.log(text));
console.log("registered");

Le script affiche « registered » avant que le gestionnaire n’affiche « draft ». Une valeur immédiatement disponible ne rend pas le gestionnaire synchrone.

Il est essentiel de passer une fonction. then(console.log("draft")) affiche « draft » pendant l’enregistrement et passe undefined comme gestionnaire. Utilise then(() => console.log("draft")) lorsque le message doit s’afficher plus tard. then(console.log) passe la fonction d’affichage elle-même, qui reçoit donc la valeur.

Effectuer le nettoyage après une réussite ou un échec

finally est utile pour masquer un indicateur de chargement ou réactiver un bouton après l’acquittement d’une opération. Sa fonction de rappel ne reçoit ni valeur ni erreur en argument.

Promise.resolve(4)
  .finally(() => console.log("Cleanup"))
  .then(value => console.log(value));

La console affiche « Cleanup », puis « 4 ». Renvoyer une valeur ordinaire depuis la fonction de rappel de nettoyage ne remplace pas 4. Une promesse renvoyée peut retarder l’étape suivante jusqu’à la fin du nettoyage. Si le nettoyage lève une erreur ou renvoie une promesse rejetée, cet échec devient la nouvelle issue de la chaîne.

Sur une page, on définit généralement un état de chargement avant de commencer, on traite le résultat dans then, on signale l’échec dans catch et on réinitialise l’état de chargement dans finally. Place les opérations qui dépendent du résultat dans then ou catch, où l’argument nécessaire existe.

Distinguer les abonnements d’une chaîne
const p = Promise.resolve(4);
p.then(value => value * 2);
p.then(value => console.log(value));

Ce sont deux abonnements distincts à p. Tous deux reçoivent 4. La multiplication appartient à la nouvelle promesse renvoyée par le premier then ; elle ne modifie pas p et ne transmet rien au second abonnement.

Relie-les pour transmettre la valeur transformée :

p.then(value => value * 2)
  .then(value => console.log(value));

Le dernier gestionnaire reçoit maintenant 8. La différence tient à la promesse à laquelle chaque gestionnaire est associé.

L’objet renvoyé reste une promesse

Dans const next = p.then(value => value * 2), next est une nouvelle promesse, et non le nombre 8. Le gestionnaire peut s’exécuter après la fin du script qui l’entoure et peut lui-même renvoyer une opération différée. Utilise un autre gestionnaire ou await pour obtenir la valeur. Traiter immédiatement next comme un nombre fait perdre cette information sur le moment où la valeur sera disponible.

Points clés

  • Utilise then pour les valeurs, catch pour les rejets et finally pour le nettoyage.
  • Passe des fonctions comme gestionnaires.
  • Chaque then renvoie une nouvelle promesse.
  • Des gestionnaires distincts associés à une même promesse reçoivent son issue initiale.
  • Un nettoyage réussi dans finally conserve l’issue précédente ; un nettoyage qui échoue la remplace.

3.3 Enchaîne des promesses

Une chaîne de promesses transmet le résultat d’un gestionnaire au suivant. Chaque maillon doit renvoyer la valeur ou la promesse dont les maillons suivants ont besoin.

Transmettre des valeurs dans la chaîne
Promise.resolve(3)
  .then(count => count * 4)
  .then(total => total + 2)
  .then(total => console.log(total));

Le premier gestionnaire reçoit 3 et renvoie 12. Le deuxième reçoit 12 et renvoie 14. Le dernier affiche « 14 ». Une fonction fléchée dont le corps est une expression renvoie automatiquement cette expression ; un corps de fonction entre accolades a besoin d’un return explicite pour transmettre une valeur.

Renvoyer une promesse pour une étape dépendante
function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
function makeCode() {
  return wait(100).then(() => "P4");
}
function makeLabel(code) {
  return wait(200).then(() => "Parcel " + code);
}
makeCode()
  .then(code => makeLabel(code))
  .then(label => console.log(label));

makeCode fournit « P4 » après environ 100 ms. Le gestionnaire suivant renvoie la promesse de makeLabel. La chaîne suit cette promesse, attend environ 200 ms de plus et transmet « Parcel P4 » au dernier gestionnaire. Le code appelant reçoit un libellé, et non une promesse imbriquée dans la valeur.

Repérer un maillon rompu

Compare ce gestionnaire intermédiaire avec celui-ci :

.then(code => {
  makeLabel(code);
})

Il lance makeLabel mais ne renvoie rien. Sa nouvelle promesse est tenue avec undefined sans attendre le libellé. Le gestionnaire suivant reçoit donc undefined après l’étape du code, tandis que la préparation du libellé se poursuit séparément. Les erreurs de cette opération séparée ne se propagent plus non plus dans la chaîne externe.

Corrige-le avec return makeLabel(code); entre les accolades ou retire les accolades pour renvoyer l’expression. La même règle s’applique lorsqu’un gestionnaire lance une pause : .then(() => wait(200)) attend ; .then(() => { wait(200); }) n’attend pas.

Réduire l’imbrication et conserver les valeurs nécessaires

Placer un autre then profondément dans le premier gestionnaire peut recréer l’imbrication des fonctions de rappel. Renvoie la promesse interne et place le gestionnaire suivant au niveau externe. Cela conserve un seul parcours pour les délais, les valeurs et les erreurs.

Chaque gestionnaire possède sa propre portée locale. Si une étape ultérieure a besoin à la fois du code et du libellé, renvoie un objet qui les contient :

makeCode()
  .then(code => makeLabel(code).then(label => ({ code, label })))
  .then(pair => console.log(pair.code + ": " + pair.label));

Ce petit gestionnaire interne construit la valeur combinée. La promesse issue de son enregistrement est renvoyée et reste donc reliée à la chaîne. Une fonction asynchrone peut aussi conserver les deux résultats dans des variables locales ordinaires.

Un rejet ignore les gestionnaires de réussite suivants jusqu’à atteindre un gestionnaire de rejet. Un catch final peut gérer les échecs de toutes les étapes précédentes reliées à la chaîne. Les opérations dépendantes ont leur place dans cette séquence ; les opérations indépendantes peuvent être lancées ensemble avec Promise.all.

Points clés

  • Renvoie la valeur dont le gestionnaire suivant a besoin.
  • Renvoyer une promesse oblige la chaîne à attendre son issue.
  • Le corps d’une fonction fléchée entre accolades a besoin de return.
  • Garde les opérations dépendantes et leurs erreurs reliées à la chaîne externe.
  • Transmets les données combinées lorsque des étapes ultérieures ont besoin de valeurs locales précédentes.
4

Écris du code asynchrone avec async et await

Les fonctions asynchrones permettent d’écrire les étapes utilisant des promesses dans l’ordre où tu veux qu’elles se déroulent. Les valeurs peuvent rester dans des variables nommées et await indique les endroits où la fonction se suspend. Découvre l’effet de cette pause sur le code appelant, convertis du code plus ancien sous cette forme et repère les erreurs qui laissent une promesse là où une valeur est nécessaire. Le comportement des boucles demande une attention particulière : une fonction de rappel asynchrone ne fait pas attendre la fonction qui l’appelle.

4.1 Écris des fonctions asynchrones et utilise await

Une fonction asynchrone renvoie toujours une promesse. À l’intérieur, await suspend cette fonction jusqu’à ce qu’une valeur soit disponible, ce qui permet de lire les étapes dépendantes de haut en bas.

Renvoyer une valeur par une promesse
async function getCount() {
  return 6;
}
getCount().then(count => console.log(count));

Appeler getCount() donne une promesse tenue avec 6. Le gestionnaire affiche « 6 ». Si la fonction lève une erreur, la promesse qu’elle renvoie est rejetée. Si elle renvoie une autre promesse, la fonction asynchrone suit l’issue future de cette promesse.

Tu peux déclarer une fonction asynchrone avec async function name(), une fonction fléchée asynchrone comme const name = async () => {}, ou une méthode d’objet asynchrone. Dans tous les cas, elle renvoie une promesse.

Suspendre l’exécution avec await
function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
async function showSteps() {
  console.log("Step one");
  await wait(300);
  console.log("Step two");
}
showSteps();
console.log("Caller continues");

La console affiche d’abord « Step one », puis « Caller continues ». Environ 300 ms plus tard, elle affiche « Step two ». L’appel de la fonction exécute son corps de façon synchrone jusqu’au premier await. La pause rend le contrôle au code appelant. Une fois la promesse tenue, le reste de showSteps reprend par la file de microtâches.

Await suspend sa fonction, pas le thread entier. D’autres tâches prêtes peuvent s’exécuter pendant l’attente. Un long calcul synchrone avant ou après await peut toujours bloquer le thread pendant son exécution.

Lire une valeur ou recevoir une erreur

Une promesse tenue fournit sa valeur : const count = await getCount(); affecte 6 à count. Une promesse rejetée lève sa raison à la ligne de await. Entoure l’opération attendue de try et catch lorsque cette fonction doit gérer l’échec.

await accepte aussi des valeurs ordinaires. Dans const count = await 6;, le résultat est toujours 6, mais la continuation de la fonction est différée. Elle ne devient pas synchrone simplement parce qu’aucune opération n’avait besoin d’être attendue.

Vérifier où placer await

Utilise await dans la fonction asynchrone dont le corps le contient. Il est aussi autorisé au niveau supérieur d’un module JavaScript. Le corps d’une fonction ordinaire ne peut pas contenir await ; une fonction asynchrone externe ne rend pas asynchrone une fonction de rappel ordinaire imbriquée.

Le code appelant reçoit toujours une promesse. Pour utiliser la valeur finale, attends-la depuis une autre fonction asynchrone ou ajoute then. Par exemple, const total = getCount(); stocke une promesse ; cette instruction ne stocke pas 6.

Un gestionnaire d’événements peut lui-même être asynchrone. Il peut attendre une étape de préparation avant de mettre une page à jour. Prévois une gestion des erreurs propre à cette action, car le déclenchement de l’événement n’attend pas la promesse renvoyée par le gestionnaire. Au niveau supérieur d’un programme, un appel comme showSteps().catch(console.error) associe un gestionnaire à un échec imprévu.

Points clés

  • Une fonction asynchrone renvoie une promesse correspondant à sa valeur de retour ou à l’erreur qu’elle lève.
  • Le code avant le premier await s’exécute pendant l’appel.
  • Après await, l’exécution reprend plus tard avec une valeur ou lève la raison d’un rejet.
  • Await s’utilise dans une fonction asynchrone ou au niveau supérieur d’un module.

4.2 Réécris des chaînes de promesses et des API à fonctions de rappel avec async et await

Une chaîne de promesses peut devenir une fonction asynchrone sans changer ses dépendances. Chaque résultat reçoit une variable locale et chaque étape attendue ne commence qu’une fois disponible le résultat précédent dont elle a besoin.

Remplacer les gestionnaires par des affectations avec attente
function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
function getUser(id) {
  return wait(100).then(() => ({ id, name: "Nia" }));
}
function getOrders(user) {
  return wait(200).then(() => [user.name + "-1", user.name + "-2"]);
}
async function showOrders(id) {
  const user = await getUser(id);
  const orders = await getOrders(user);
  console.log(user.name + ": " + orders.length + " orders");
}
showOrders(8).catch(console.error);

Le premier await fournit un utilisateur. Alors seulement, getOrders(user) peut commencer. Après environ 300 ms au total, la fonction affiche « Nia: 2 orders ». user et orders sont tous deux accessibles dans la portée de cette dernière ligne. Dans une chaîne, le paramètre de chaque gestionnaire appartiendrait à une portée locale distincte.

La chaîne correspondante renverrait getOrders(user) depuis le premier gestionnaire. La réécrire avec await rend cette attente explicite tout en conservant l’ordre. Un catch final de chaîne devient un try/catch autour des étapes attendues ; finally devient un bloc de nettoyage.

Convertir une API à fonctions de rappel en API à promesses

Ajouter async à une fonction enveloppante ne fait pas de la valeur différée d’une API à fonctions de rappel sa valeur de retour. Relie la fonction de rappel à l’acquittement de la promesse :

function readTag(id, callback) {
  setTimeout(() => {
    if (id <= 0) callback(new Error("Invalid tag"));
    else callback(null, "Tag " + id);
  }, 100);
}
function readTagAsync(id) {
  return new Promise((resolve, reject) => {
    readTag(id, (err, tag) => {
      if (err) {
        reject(err);
        return;
      }
      resolve(tag);
    });
  });
}

Dans une fonction asynchrone, const tag = await readTagAsync(8); donne « Tag 8 ». L’appeler avec 0 lève à la place « Invalid tag » au niveau de await. Une réussite résout la promesse de la fonction enveloppante ; un échec la rejette. L’adaptateur change la façon dont l’issue est transmise, pas ce que fait l’opération sous-jacente.

Cette conversion s’appelle la promessification. Pour les API ordinaires qui produisent un seul résultat et suivent la convention de l’erreur en premier, Node.js fournit aussi util.promisify, et de nombreux modules intégrés disposent déjà de variantes utilisant des promesses, comme fs/promises.

Garder un parcours clair

Les minuteries deviennent des pauses grâce à une fonction utilitaire wait qui renvoie une promesse. Une boucle asynchrone peut afficher une étape, attendre la pause, puis commencer l’itération suivante. Avec des fonctions de rappel, il faudrait planifier l’étape suivante dans la fonction de rappel précédente.

Les promesses, les chaînes et les fonctions asynchrones fonctionnent ensemble : une fonction asynchrone peut attendre une chaîne et le code appelant peut ajouter then à la promesse qu’elle renvoie. Dans une fonction, utilise la forme qui permet de suivre facilement les dépendances et la gestion des erreurs. Un constructeur Promise supplémentaire est utile pour adapter une fonction de rappel, mais les opérations qui renvoient déjà des promesses peuvent être attendues directement.

Points clés

  • Chaque étape dépendante d’une chaîne peut devenir une affectation avec attente.
  • Les variables locales permettent de retrouver les résultats précédents plus loin dans la fonction asynchrone.
  • Promessifie les fonctions de rappel en associant les erreurs à reject et les résultats à resolve.
  • Les API existantes qui renvoient des promesses peuvent être attendues directement.

4.3 Évite les erreurs courantes avec async et await

Le code asynchrone peut ressembler à du code synchrone tout en transmettant des promesses entre les fonctions. De nombreux bogues viennent d’une lecture trop précoce de la valeur future ou de la supposition qu’une fonction utilitaire attend des fonctions de rappel qu’elle ignore.

Attendre la valeur avant de l’utiliser
async function getQuantity() {
  return 18;
}
async function total() {
  const quantity = await getQuantity();
  console.log(quantity * 3);
}
total().catch(console.error);

Ce code affiche « 54 ». Sans await, quantity contiendrait une promesse. Multiplier cette promesse par 3 produit NaN, et non un calcul différé qui se met automatiquement à jour.

Une condition présente le même piège. Une vérification asynchrone qui renvoie false renvoie tout de même un objet promesse, et les objets sont des valeurs vraies. Utilise if (await allowed()) dans une fonction asynchrone lorsque la branche dépend du booléen futur. Tester if (allowed()) revient à tester l’objet lui-même.

forEach ne collecte pas les promesses des fonctions de rappel
function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
async function labelAll(ids) {
  ids.forEach(async id => {
    await wait(100);
    console.log("Label " + id);
  });
  console.log("Labels finished");
}
labelAll([4, 9]).catch(console.error);

« Labels finished » apparaît avant les libellés. forEach appelle les deux fonctions de rappel, ignore les promesses qu’elles renvoient et termine sa propre itération synchrone. Même await ids.forEach(...) attendrait undefined, et non le travail des fonctions de rappel. Un échec dans ces promesses ignorées se situe aussi hors de la promesse renvoyée par labelAll.

Pour un traitement ordonné, écris une boucle ordinaire :

for (const id of ids) {
  await labelOne(id);
}
console.log("Labels finished");

Ici, labelOne est une opération qui renvoie une promesse. Chaque élément commence après la fin du précédent. Pour des éléments indépendants, utilise await Promise.all(ids.map(id => labelOne(id))); avant le dernier affichage. map collecte les promesses renvoyées et Promise.all donne au code appelant une seule promesse pour leur achèvement.

Distinguer l’indépendance de la syntaxe

Attendre immédiatement chaque opération rend les attentes séquentielles. Pour des attentes indépendantes de 1 000, 2 000 et 1 500 ms, cela prend environ 4 500 ms. Lancer les trois et les combiner prend environ 2 000 ms. Une étape qui a besoin d’un résultat précédent doit toujours l’attendre.

Garder les échecs reliés

Une fonction imbriquée a besoin de son propre mot-clé async pour utiliser await, mais ce mot-clé seul ne fait pas attendre le résultat par le code appelant. Vérifie les deux côtés : la fonction de rappel renvoie-t-elle une promesse et le code appelant l’utilise-t-il ?

Pour une opération lancée volontairement sans attendre son achèvement, ajoute un gestionnaire de rejet comme backgroundTask().catch(console.error). Vérifie aussi les retours dans les fonctions enveloppantes asynchrones : async function prepare() { await wait(100); } est tenue avec undefined. Attendre une étape et renvoyer son résultat sont deux décisions distinctes.

Renvoyer les résultats du groupe corrigé
function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
async function prepareItem(id) {
  await wait(50);
  return "Item " + id;
}
async function prepareAll(ids) {
  return await Promise.all(ids.map(id => prepareItem(id)));
}
prepareAll([6, 2]).then(items => console.log(items.join(", ")));

Chaque fonction de rappel de map renvoie une promesse et map conserve ces promesses dans un tableau. Promise.all attend les deux et fournit ["Item 6", "Item 2"]. La fonction prepareAll renvoie ce tableau par sa propre promesse : le code appelant affiche donc « Item 6, Item 2 » après la fin du groupe.

Retirer le return de prepareAll attendrait toujours le groupe, mais le code appelant recevrait undefined. Remplacer map par forEach ferait perdre le tableau de promesses. Vérifie séparément la collecte, l’attente et le retour lorsque tu corriges une action portant sur plusieurs éléments.

Points clés

  • Attends un nombre ou un booléen futur avant de l’utiliser.
  • forEach ignore les promesses renvoyées par les fonctions de rappel asynchrones.
  • Utilise for...of pour les opérations séquentielles ou map avec Promise.all pour les opérations indépendantes.
  • Une fonction de rappel imbriquée a besoin de son propre mot-clé async.
  • Associe un gestionnaire de rejet aux opérations que tu choisis de ne pas attendre.
5

Gère les erreurs dans le code asynchrone

Une opération qui échoue fait partie du déroulement du programme. Le code doit décider s’il récupère après l’erreur, fait une nouvelle tentative, signale l’échec ou le transmet à un appelant capable de décider. Suis les échecs dans les chaînes de promesses et dans les appels attendus, puis utilise du code de nettoyage qui s’exécute quelle que soit l’issue. Enfin, place la gestion des erreurs à la limite d’une action afin que l’utilisateur reçoive un message utile et que tu conserves la cause technique.

5.1 Gère les rejets dans les chaînes de promesses

Le rejet d’une promesse suit la chaîne à laquelle elle est reliée jusqu’à ce qu’un gestionnaire de rejet le traite. Comprendre ce que ce gestionnaire renvoie permet de savoir si la chaîne a récupéré après l’erreur ou si elle reste en échec.

Suivre un rejet au-delà des gestionnaires de réussite
Promise.resolve(8)
  .then(value => {
    throw new Error("Count rejected");
  })
  .then(value => console.log("Unused: " + value))
  .catch(err => {
    console.log(err.message);
    return 2;
  })
  .then(value => console.log("Using " + value));

L’exception rejette la nouvelle promesse renvoyée par le premier then. Le gestionnaire de réussite suivant est ignoré : « Unused » ne s’affiche donc jamais. Le catch affiche « Count rejected » et renvoie 2. Ce retour tient le maillon suivant et le dernier gestionnaire affiche donc « Using 2 ».

Une promesse explicitement rejetée et une exception levée dans un gestionnaire empruntent le même chemin de rejet. C’est pourquoi un seul catch final peut gérer les échecs de plusieurs étapes précédentes reliées à la chaîne.

Choisir entre récupération et propagation

Un gestionnaire de rejet qui renvoie une valeur récupère après l’erreur avec cette valeur. Ne rien renvoyer permet aussi de récupérer, mais avec undefined. Consigner un échec ne revient donc pas à laisser la chaîne rejetée :

Promise.reject(new Error("Label missing"))
  .catch(err => console.log(err.message))
  .then(value => console.log(value));

Le dernier gestionnaire reçoit undefined. Si le code suivant exige un libellé réel, cette récupération silencieuse est probablement incorrecte. Renvoie une solution de repli utilisable ou relance l’erreur.

function reportAndRethrow(err) {
  console.error(err);
  throw err;
}

Utiliser cette fonction dans catch consigne l’erreur et laisse la promesse suivante rejetée avec la même raison. Un appelant situé plus loin dans la chaîne peut décider quoi faire.

Placer le gestionnaire après les opérations qu’il protège

Un catch gère les échecs qui le précèdent. S’il récupère après l’erreur, les étapes suivantes s’exécutent normalement et leurs nouveaux échecs ont besoin d’un gestionnaire ultérieur. Un gestionnaire placé au milieu ne peut pas intercepter des erreurs qui ne se sont pas encore produites.

Il existe aussi une différence importante entre .then(success, failure) et .then(success).catch(failure). Les deux gestionnaires d’un même then réagissent à l’issue de la promesse reçue. Son gestionnaire d’échec n’intercepte pas une erreur levée par son propre gestionnaire de réussite. Cette erreur appartient à la nouvelle promesse renvoyée par l’appel : un catch ultérieur est donc nécessaire.

Conserver les erreurs utiles

Rejette les promesses avec des objets Error pour que les gestionnaires puissent lire err.message et err.name. Lever une chaîne ou rejeter une promesse avec une chaîne est autorisé, mais le code qui attend les champs d’un objet Error ne les recevra pas. Conserve l’erreur initiale lors de la propagation d’un échec, sauf si l’ajout de contexte aide le code appelant à comprendre quelle opération a échoué.

Points clés

  • Les rejets ignorent les gestionnaires de réussite jusqu’à atteindre un gestionnaire de rejet.
  • Un retour depuis catch permet de récupérer après l’erreur ; sans valeur renvoyée, la récupération se fait avec undefined.
  • Relance l’exception pour que l’échec continue de se propager.
  • Un catch protège les étapes reliées qui le précèdent.
  • Un gestionnaire de rejet de then ne peut pas intercepter une exception levée par le gestionnaire de réussite du même then.

5.2 Utilise try, catch et finally avec await

try, catch et finally permettent à une fonction asynchrone de gérer les échecs à l’endroit où elle les attend. Utilise cette structure pour regrouper le traitement du résultat, la récupération et le nettoyage.

Une erreur transfère le contrôle

Un objet Error décrit un échec. new Error("Label missing") a pour message « Label missing » et pour nom « Error » ; les outils de débogage peuvent aussi afficher sa pile. Les erreurs intégrées ont des types comme TypeError.

throw arrête l’exécution normale à cet endroit et transfère le contrôle au catch applicable le plus proche. Le code situé après le traitement peut encore s’exécuter lorsque la fonction intercepte sa propre erreur. Lève des objets Error pour que les gestionnaires suivants reçoivent des champs utiles.

Attendre dans le bloc protégé
async function run() {
  console.log("Working");
  try {
    await Promise.reject(new Error("Device busy"));
    console.log("Complete");
  } catch (err) {
    console.log("Failed: " + err.message);
  } finally {
    console.log("Controls enabled");
  }
}
run().catch(console.error);

La promesse rejetée lève une erreur à la ligne de await. Le reste de try est ignoré. La console affiche « Working », « Failed: Device busy », puis « Controls enabled ». Une opération réussie atteindrait « Complete » et exécuterait tout de même le même nettoyage.

Utilise finally pour un indicateur de chargement, l’état d’un bouton ou une autre ressource qui doit être réinitialisée quelle que soit l’issue. Il s’exécute même lorsque try ou catch contient une instruction return. Évite que le nettoyage lève une erreur, sauf si ce nouvel échec doit volontairement remplacer l’issue précédente. Un return dans finally peut remplacer un retour ou une exception antérieurs : évite donc de l’utiliser pour un nettoyage ordinaire.

Ici, renvoyer une promesse est différent de l’attendre
async function readSetting() {
  try {
    return await Promise.reject(new Error("Missing setting"));
  } catch {
    return "light";
  }
}
readSetting().then(value => console.log(value));

Ce code affiche « light ». La fonction attend dans try : le rejet atteint donc le catch local. Retirer await renvoie immédiatement la promesse rejetée ; la fonction adopte son rejet, mais le catch local ne traite pas cette issue ultérieure. Le code appelant devrait l’intercepter.

Donner à chaque échec un périmètre adapté

Un seul try peut couvrir un groupe d’attentes lorsque toute l’action doit s’arrêter si une étape échoue. Donne à une étape facultative un périmètre plus restreint si elle peut récupérer indépendamment. Par exemple, const settings = await loadSettings().catch(() => ({ theme: "light" })); utilise un objet par défaut et continue.

Une variable déclarée dans try a une portée de bloc. Si le code après le bloc en a besoin, déclare let result; avant try ou termine les opérations qui dépendent du résultat dans try. Ne déplace pas une valeur hors de sa portée simplement pour garder un affichage final à l’endroit que tu préfères.

Lorsque la fonction en cours ne peut pas récupérer après l’erreur, laisse le rejet atteindre le code appelant. L’intercepter uniquement pour le masquer empêche cet appelant de prendre une décision utile.

Points clés

  • Les rejets attendus lèvent une erreur à la ligne de await.
  • Catch peut récupérer après une erreur, la signaler ou la relancer.
  • Finally s’exécute quelle que soit l’issue, y compris en cas de return.
  • Utilise return await dans try lorsque le catch local doit gérer le rejet de l’opération renvoyée.
  • Les résultats à portée de bloc restent dans leur bloc try.

5.3 Rends les échecs visibles et prévois une récupération adaptée

Une action a besoin d’un périmètre d’interception des erreurs : un endroit qui reçoit son échec final et choisit une réponse. Sans ce périmètre, une promesse peut être rejetée alors que personne ne gère son issue.

Gérer le dernier chemin

Un rejet non géré est un rejet qui n’a toujours pas de gestionnaire lorsque l’hôte effectue sa vérification. La gestion peut utiliser catch, l’argument de rejet de then ou try/catch autour de await. Un navigateur signale le problème et peut déclencher unhandledrejection. Node.js s’arrête par défaut en cas de rejet non géré selon sa politique habituelle : en laisser un sans gestionnaire peut donc mettre fin à un programme.

Une action comme main() ou un gestionnaire de clic asynchrone doit gérer sa promesse finale. Les fonctions de niveau inférieur peuvent transmettre les échecs vers le haut, mais le parcours doit aboutir à un endroit où une décision est prise. Un écouteur global de rejets peut aider à consigner les échecs manqués ; il ne peut pas choisir la meilleure récupération pour chaque action.

Un catch vide passe l’échec sous silence. Consigne les détails techniques avec console.error(err) et affiche un message clair si l’action de l’utilisateur a échoué. Un message comme « Le libellé n’a pas pu être enregistré. Réessaie dans quelques instants. » indique à l’utilisateur une action possible sans exposer de trace de pile.

Ajouter du contexte sans perdre la cause
async function prepareLabel() {
  try {
    return await Promise.reject(new Error("Device offline"));
  } catch (err) {
    throw new Error("Could not prepare label", { cause: err });
  }
}
prepareLabel().catch(err => {
  console.log(err.message);
  console.log(err.cause.message);
});

Ce code affiche « Could not prepare label » et « Device offline ». Le message externe indique l’action qui a échoué. La propriété cause conserve l’erreur de niveau inférieur pour le diagnostic. L’option de cause d’Error fait partie d’ECMAScript 2022.

Relancer une nouvelle opération, avec une limite
function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
async function withRetry(task, attempts) {
  for (let attempt = 1; attempt <= attempts; attempt++) {
    try {
      return await task();
    } catch (err) {
      if (attempt === attempts) throw err;
      await wait(200);
    }
  }
}

Appelle cette fonction avec une fonction qui lance une nouvelle tentative et une limite exprimée par un entier positif. Si task échoue deux fois et réussit à son troisième appel, une limite de quatre arrête les essais au troisième appel et renvoie sa valeur. Si les quatre tentatives échouent, la quatrième erreur est relancée. Le délai n’a lieu qu’entre les tentatives.

return await garde le rejet dans ce try, où catch peut lancer une nouvelle tentative. Passer une promesse déjà rejetée au lieu d’une fonction de tâche ne relancerait pas l’opération.

Fais une nouvelle tentative lorsqu’un échec peut être temporaire. Utilise une solution de repli lorsque la fonctionnalité peut fonctionner avec des données par défaut. Arrête l’opération et informe l’utilisateur lorsqu’elle ne peut pas réussir. Si une fonction de niveau inférieur ne peut pas faire ce choix, conserve l’erreur et laisse le code appelant décider.

Points clés

  • Toute action asynchrone a besoin d’un gestionnaire pour son échec final.
  • Un catch vide masque des informations utiles sur l’échec.
  • La cause d’un objet Error conserve l’échec initial tout en ajoutant du contexte.
  • Fais une nouvelle tentative en rappelant une tâche, avec un nombre limité de tentatives.
  • Choisis une nouvelle tentative, une solution de repli, l’arrêt ou la propagation selon l’échec.
6

Exécute des tâches asynchrones en parallèle

Certaines opérations ont besoin de résultats précédents ; d’autres peuvent commencer ensemble. Identifie cette dépendance avant de choisir où placer await. Tu vas combiner des opérations indépendantes, conserver les résultats dans le bon ordre et choisir si ton programme a besoin de toutes les réussites, de toutes les issues, du premier acquittement ou de la première réussite. Chaque choix change ce que signifie un échec et la durée d’attente du code appelant.

6.1 Lance des tâches ensemble et attends leurs résultats avec Promise.all

Des opérations asynchrones indépendantes peuvent attendre en même temps. Le choix de les lancer ensemble dépend des données dont elles ont besoin, et non de l’ajout du mot async.

Lancer les opérations indépendantes avant de toutes les attendre
function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
function makePart(name, ms) {
  return wait(ms).then(() => name);
}
async function assemble() {
  const parts = await Promise.all([
    makePart("cover", 1000),
    makePart("pages", 2000),
    makePart("label", 1500)
  ]);
  console.log(parts.join(", "));
}
assemble().catch(console.error);

Les trois appels commencent avant que Promise.all n’attende leurs résultats. Environ 2 000 ms plus tard, le tableau contient ["cover", "pages", "label"]. Attendre chaque appel avant de lancer le suivant prendrait environ 4 500 ms. Les délais des minuteries sont approximatifs : les durées réelles peuvent donc être plus longues.

Ici, en parallèle signifie que les attentes se chevauchent. Les gestionnaires de promesses s’exécutent toujours un par un sur le thread principal. Appeler trois fonctions synchrones lourdes dans le tableau exécuterait ces calculs les uns après les autres ; Promise.all ne les déplacerait pas vers des threads distincts.

Les résultats conservent leur place dans les entrées

Le libellé se termine avant les pages, mais reste troisième dans le tableau. Promise.all conserve l’ordre des entrées, et non l’ordre d’achèvement. La déstructuration permet de nommer ces positions :

const [cover, pages] = await Promise.all([
  makePart("cover", 1000),
  makePart("pages", 2000)
]);

Utilise ce code dans une fonction asynchrone. Pour une collection, ids.map(id => loadItem(id)) lance une opération qui renvoie une promesse par identifiant et donne à Promise.all le tableau de promesses. N’attends pas chaque élément dans une boucle s’ils sont tous indépendants et doivent se chevaucher.

Un échec met fin à l’attente combinée

Promise.all est rejetée dès qu’une entrée est rejetée. Si une partie échoue après environ 300 ms, un catch peut alors recevoir cette raison ; il n’a pas besoin d’attendre la fin de l’opération réussie qui prend le plus de temps.

Les autres opérations continuent de s’exécuter. Leurs effets de bord peuvent encore se produire, mais la promesse combinée ne sera pas tenue plus tard avec leurs valeurs. Cette règle d’échec immédiat (fail-fast) est utile lorsque l’étape suivante exige tous les résultats.

Respecter les dépendances et ajouter rapidement des gestionnaires

Si une opération a besoin d’un utilisateur produit par une autre, obtiens d’abord cet utilisateur. Les appels suivants ne peuvent être combinés que s’ils sont indépendants les uns des autres une fois cet utilisateur disponible.

Lancer deux promesses et les attendre séparément fait bien se chevaucher leurs attentes, mais la seconde peut être rejetée avant que le code n’atteigne son await. Si elle n’a toujours pas de gestionnaire lorsque l’hôte vérifie les rejets, un rejet non géré peut être signalé. Combiner rapidement les promesses avec Promise.all associe un gestionnaire aux deux entrées et donne au code appelant un seul chemin pour les échecs.

Les valeurs ordinaires sont autorisées parmi les entrées et conservent leur place. Promise.all([]) est déjà tenue avec un tableau vide. Un gestionnaire qui lui est associé s’exécute toujours de façon asynchrone.

Points clés

  • Lance les opérations indépendantes ensemble pour faire se chevaucher leurs attentes.
  • Promise.all renvoie les résultats dans l’ordre des entrées.
  • Un seul rejet rejette la promesse combinée sans annuler les autres entrées.
  • Les étapes dépendantes ont toujours besoin des résultats précédents.
  • Combine rapidement les promesses lancées pour garder leurs chemins d’erreur reliés.

6.2 Choisis entre Promise.allSettled, Promise.race et Promise.any

Le bon combinateur de promesses dépend de ce qui constitue un résultat utile. Détermine si tu as besoin de toutes les réussites, de toutes les issues, du premier acquittement ou de la première réussite.

Conserver les résultats partiels avec allSettled

Promise.allSettled attend chaque entrée et renvoie des objets décrivant les issues dans l’ordre des entrées. Une réussite devient { status: "fulfilled", value } ; un échec devient { status: "rejected", reason }. Une entrée rejetée ne rejette pas la promesse combinée.

Promise.allSettled([
  Promise.resolve("Map ready"),
  Promise.reject(new Error("Chart unavailable"))
]).then(results => {
  for (const result of results) {
    if (result.status === "fulfilled") console.log(result.value);
    else console.log(result.reason.message);
  }
});

Ce code affiche « Map ready » et « Chart unavailable ». Il convient à des panneaux indépendants, lorsqu’un panneau qui fonctionne reste utile même si un autre échoue. Lis value uniquement dans un objet correspondant à une promesse tenue et reason dans un objet correspondant à une promesse rejetée.

Laisser le premier acquittement décider avec race

Promise.race suit la première entrée acquittée, qu’elle soit tenue ou rejetée. Un échec après 100 ms l’emporte sur une réussite après 200 ms. C’est utile pour un délai d’expiration :

function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
function timeout(ms) {
  return new Promise((_, reject) => {
    setTimeout(() => reject(new Error("Time limit reached")), ms);
  });
}
Promise.race([
  wait(600).then(() => "Prepared"),
  timeout(250)
]).then(console.log).catch(err => console.log(err.message));

Le délai d’expiration provoque un rejet en premier : la console affiche donc « Time limit reached ». L’opération de 600 ms continue de s’exécuter. Une course acquitte la promesse combinée du code appelant ; elle n’annule pas les opérations perdantes.

Attendre la première réussite avec any

Promise.any ignore les entrées qui échouent tant qu’une réussite reste possible. Si une opération échoue après 100 ms et qu’une autre est tenue après 200 ms, elle donne la valeur de cette dernière. Un rejet plus rapide ne l’emporte pas.

Si toutes les entrées sont rejetées, any est rejetée avec une AggregateError. Son tableau errors conserve les raisons des rejets dans l’ordre des entrées. Le code appelant peut ainsi examiner pourquoi chaque tentative a échoué, même si les échecs sont arrivés dans un ordre différent.

Comparer les règles de décision
  • all : toutes les valeurs sont nécessaires ; rejet au premier rejet.
  • allSettled : toutes les issues sont nécessaires ; attente de tous les objets de résultat.
  • race : le premier acquittement décide, y compris en cas d’échec.
  • any : la première promesse tenue décide ; rejet uniquement si toutes sont rejetées.

Sans entrée, all et allSettled sont tenues avec []. any est rejetée avec une AggregateError, car aucune réussite n’est possible. race reste en attente, car rien ne peut l’acquitter.

Les quatre sont pris en charge dans les navigateurs actuels et dans Node.js. all et race sont entrées dans ECMAScript en 2015, allSettled en 2020 et any en 2021.

Comparer une paire d’issues

Supposons que les deux opérations commencent maintenant : la première entrée échoue après environ 100 ms, tandis que la seconde est tenue avec « usable » après environ 300 ms. Appliquer chaque combinateur à cette même paire donne des résultats différents :

  • All est rejetée vers 100 ms avec l’erreur de la première entrée, car chaque entrée doit réussir.
  • AllSettled est tenue vers 300 ms avec un objet de résultat rejeté suivi d’un objet de résultat tenu, en conservant l’ordre des entrées.
  • Race est rejetée vers 100 ms, car c’est le premier acquittement.
  • Any est tenue vers 300 ms avec « usable », car l’échec précédent ne peut pas fournir de réussite.

All et race sont toutes deux rejetées dans ce cas, mais elles utilisent des règles différentes. Si la première entrée rapide réussissait et que la seconde échouait plus tard, race conserverait sa réussite initiale tandis que all serait rejetée lors de l’échec ultérieur. Choisis en fonction de l’issue nécessaire, et non du délai observé dans un exemple.

Points clés

  • allSettled rapporte chaque réussite et chaque échec dans l’ordre des entrées.
  • race suit le premier acquittement, y compris un rejet.
  • any accepte la première réussite et n’est rejetée que si toutes les entrées sont rejetées.
  • Un délai d’expiration avec race laisse les opérations perdantes s’exécuter.
  • Une entrée vide pour race reste en attente ; une entrée vide pour any provoque un rejet.
  • Choisis le combinateur selon l’issue dont le code appelant a réellement besoin.

JavaScript asynchrone : exemples

6 Leçons Interactives

1

Prévois ce qui s’exécute maintenant et plus tard

14 étapes
Suis un petit script dans la pile et les files, puis utilise le même modèle temporel pour planifier et annuler des minuteries.
  1. 1
    IntroductionDistinguer le début de la fin

    Commence par distinguer les appels immédiats des fonctions de rappel enregistrées. Une minuterie peut attendre sans occuper le thread principal, mais sa fonction de rappel a toujours besoin de ce thread. Suis ce qui s’exécute pendant le script sur la pile d’appels avant de passer aux opérations en attente, une tâche ou une microtâche, car leur ordre détermine ce que tu vois en premier.

  2. 2
    ExempleEnregistrer une fonction de rappel

    Lis ce script avant de prévoir ce qu’il affiche :

    console.log("request");
    setTimeout(() => console.log("ready"), 200);
    console.log("continue");
    

    Le premier affichage s’exécute maintenant. L’appel à la minuterie enregistre une fonction et se termine : le script atteint donc immédiatement le dernier affichage. L’affichage de la fonction de rappel appartient à une tâche ultérieure ; créer cette fonction ne l’a pas appelée.

  3. 3
    Point cléL’attente n’occupe pas le thread

    La console affiche d’abord « request », « continue », puis « ready » après environ 200 ms. L’hôte gère l’attente, mais la fonction de rappel a toujours besoin du thread principal. Une longue boucle peut la retarder même après que la minuterie est prête.

  4. 4
    DéfiLa minuterie peut-elle interrompre le calcul ?

    Un script enregistre une minuterie avec un délai nul, puis effectue un long calcul synchrone. La minuterie arrive à son terme avant la fin du calcul. Sa fonction de rappel peut-elle s’exécuter pendant ce calcul ?

    ---reveal---

    Non. Le calcul conserve le thread principal jusqu’à la fin du travail en cours. Lorsque la minuterie arrive à son terme, sa fonction de rappel est placée dans une file pour plus tard ; cela ne lui donne ni un thread d’exécution distinct ni l’autorisation d’interrompre le calcul.

  5. 5
    ExplicationDistinguer deux types d’opérations différées

    Une fonction de rappel de minuterie s’exécute comme une tâche. Un gestionnaire de promesse s’exécute comme une microtâche. La pile d’appels enregistre les appels en cours d’exécution.

    Après le travail en cours, un point de contrôle des microtâches permet de vider la file de microtâches avant qu’une autre tâche puisse commencer. Toutes les microtâches ajoutées pendant ce traitement rejoignent cette même file. Pour suivre un script, conserve des listes distinctes pour les résultats immédiats, les microtâches et les tâches de minuterie.

  6. 6
    ExempleRepérer les files

    Ajoute maintenant un gestionnaire de promesse :

    console.log("request");
    setTimeout(() => console.log("timer"), 0);
    Promise.resolve().then(() => console.log("job"));
    console.log("continue");
    

    La console affiche immédiatement « request », « continue ». Le gestionnaire de promesse attend comme microtâche ; la fonction de rappel de la minuterie est une tâche. Termine le script en cours avant d’exécuter l’une ou l’autre des fonctions enregistrées.

  7. 7
    ExempleVider la file avant la tâche suivante

    Une fois le script terminé, la microtâche affiche « job ». Ce n’est qu’une fois la file de microtâches vide que la tâche de minuterie prête peut afficher « timer ».

    La console affiche au total « request », « continue », « job », « timer ». Une promesse tenue n’appelle pas son gestionnaire de façon synchrone et une minuterie dont le délai est nul ne passe pas avant les microtâches. Le navigateur peut effectuer le rendu lorsqu’une occasion se présente après ce traitement.

  8. 8
    DéfiPlacer une opération nouvellement ajoutée à la file

    Dans quel ordre les résultats s’affichent-ils ?

    Promise.resolve().then(() => console.log("a"))
      .then(() => console.log("c"));
    queueMicrotask(() => console.log("b"));
    console.log("now");
    

    ---reveal---

    « now », « a », « b », « c ». Le script place a dans la file avant b. Le gestionnaire suivant de la chaîne n’est prêt que lorsque le gestionnaire de a se termine : c rejoint donc la file derrière l’opération b qui y était déjà.

  9. 9
    ExplicationChoisir une minuterie et conserver son identifiant

    Utilise setTimeout pour un appel planifié et setInterval pour des appels répétés. Les deux renvoient un identifiant que tu peux conserver.

    const hint = setTimeout(() => console.log("Hint"), 800);
    clearTimeout(hint);
    

    Cela annule la fonction de rappel avant son exécution. Pour une minuterie périodique, passe son identifiant à clearInterval lorsque la répétition doit prendre fin. Passe une fonction à planifier ; l’appeler dans la liste des arguments l’exécute immédiatement.

  10. 10
    ConseilPrévoir les fonctions de rappel retardées

    Les délais sont exprimés en millisecondes et indiquent une attente minimale. Du code qui occupe le thread, les onglets en arrière-plan et les limites du navigateur peuvent retarder davantage les fonctions de rappel. Planifie une temporisation imbriquée après l’exécution en cours ; attends aussi la fin de son opération asynchrone lorsque les exécutions ne doivent pas se chevaucher.

  11. 11
    ExempleUtiliser la bonne liaison de boucle

    Avec let, chaque itération donne à sa fonction de rappel un indice distinct :

    for (let n = 0; n < 3; n++) {
      setTimeout(() => console.log(n), 50);
    }
    

    Les fonctions de rappel affichent « 0 », « 1 », « 2 ». Remplacer let par var leur fait partager une seule variable, dont la valeur est 3 après la boucle. Les trois affichent alors « 3 ». La fonction de rappel lit la liaison lorsqu’elle s’exécute plus tard.

  12. 12
    DéfiRedémarrer une minuterie d’attente sans activité

    Un gestionnaire utilise un délai d’anti-rebond de 300 ms. Des événements de saisie se produisent à 0 ms, 80 ms et 170 ms, puis il n’y a plus d’événement. Vers quel moment son unique action s’exécute-t-elle ?

    ---reveal---

    Environ 470 ms après le premier événement : 300 ms après le dernier événement, à 170 ms. Chaque événement annule la temporisation précédente en attente et en planifie une nouvelle. Les actions planifiées auparavant ne s’exécutent pas non plus, et un thread occupé pourrait retarder davantage l’action finale.

  13. 13
    DéfiRelier les règles temporelles

    Une minuterie est prête, mais chaque microtâche continue d’ajouter une autre microtâche à la file. Pourquoi ni la fonction de rappel de la minuterie ni la prochaine mise à jour de l’écran ne peuvent-elles avancer ?

    ---reveal---

    Le traitement de la file de microtâches ne se termine jamais : la boucle d’événements ne peut donc pas passer à la tâche suivante ni à une occasion de rendu. Le délai écoulé de la minuterie ne modifie pas cet ordre. Planifier des microtâches sans fin peut bloquer la progression tout comme une longue boucle.

  14. 14
    RécapitulatifUn suivi d’exécution réutilisable

    Suis d’abord le code immédiat, traite ensuite toutes les microtâches, puis passe aux tâches prêtes. Conserve les identifiants des minuteries pour pouvoir les annuler. Les délais sont approximatifs ; let conserve les valeurs des itérations, tandis que l’anti-rebond redémarre un délai d’attente sans activité.

2

Transmets un résultat par une fonction de rappel

9 étapes
Construis une API à fonction de rappel qui produit un seul résultat, ajoute un chemin d’erreur et détermine où placer les opérations dépendantes.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionFournir une action suivante au code appelant
  2. 2
    ExempleProduire la valeur différée
  3. 3
    LienL’API contrôle le moment de l’exécution
  4. 4
    DéfiQuelle fonction se termine ?
  5. 5
    ExempleSignaler l’une des deux issues
  6. 6
    ConseilS’arrêter avant de lire un résultat absent après un échec
  7. 7
    DéfiRepérer le périmètre actif d’interception des erreurs
  8. 8
    DéfiRelier les résultats et les échecs entre les étapes
  9. 9
    RécapitulatifSuivre chaque issue jusqu’au code qui l’utilise
3

Construis et relie les issues des promesses

12 étapes
Crée une promesse de pause, ajoute des gestionnaires d’issue et répare une chaîne d’étapes dépendantes rompue.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionUn objet pour une issue ultérieure
  2. 2
    ExempleConstruire une pause réutilisable
  3. 3
    Point cléDistinguer l’état de la résolution
  4. 4
    DéfiGérer correctement un échec tardif
  5. 5
    ExplicationAjouter le bon gestionnaire
  6. 6
    ExempleDeux abonnements conservent une même valeur
  7. 7
    DéfiLire le résultat d’un nettoyage
  8. 8
    ExempleConstruire le premier maillon
  9. 9
    ExempleFaire attendre le maillon suivant
  10. 10
    DéfiRéparer une opération détachée
  11. 11
    DéfiRelier le nettoyage à une chaîne d’étapes dépendantes
  12. 12
    RécapitulatifVérifier le chemin renvoyé
4

Réécris une séquence avec async et await

12 étapes
Transforme une fonction de rappel en opération que l’on peut attendre et choisis la bonne boucle pour plusieurs éléments.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionGarder les promesses, changer l’ordre de lecture
  2. 2
    ExempleUn appel asynchrone commence immédiatement
  3. 3
    DéfiLire la valeur renvoyée
  4. 4
    ExempleRelier une fonction de rappel à une promesse
  5. 5
    ExempleGarder les valeurs intermédiaires dans la portée
  6. 6
    DéfiAsync suffit-il à adapter le résultat ?
  7. 7
    Point cléTester la valeur, pas sa promesse
  8. 8
    ExempleforEach n’attend pas les fonctions de rappel
  9. 9
    ConseilChoisir une méthode de parcours
  10. 10
    DéfiCorriger un achèvement prématuré
  11. 11
    DéfiRelier l’adaptation et la boucle
  12. 12
    RécapitulatifExaminer les deux côtés d’un appel asynchrone
5

Garde l’échec, la récupération et le nettoyage reliés

13 étapes
Suis une action échouée dans catch, ajoute une solution de repli locale et construis une stratégie de nouvelles tentatives limitée.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionDécider de la réponse à un échec
  2. 2
    ExempleObserver une récupération avec catch
  3. 3
    Point cléConsigner l’erreur détermine aussi un retour
  4. 4
    DéfiConserver l’issue en échec
  5. 5
    ExempleAttendre là où catch peut voir l’échec
  6. 6
    ConseilRenvoyer après le traitement local
  7. 7
    DéfiChoisir la solution de repli locale
  8. 8
    LienTerminer le chemin d’erreur de l’action
  9. 9
    ExempleConserver le contexte et la cause initiale
  10. 10
    ExempleRelancer un appel, avec une limite
  11. 11
    DéfiS’arrêter après une réussite
  12. 12
    DéfiRelier la récupération au nettoyage
  13. 13
    RécapitulatifDonner une destination à chaque issue
6

Choisis ce qu’un groupe de tâches doit fournir

11 étapes
Fais se chevaucher des attentes indépendantes et choisis le combinateur adapté à l’issue nécessaire.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionCommencer par la question des dépendances
  2. 2
    ExempleLancer les deux opérations ensemble
  3. 3
    Point cléUn échec n’annule pas le groupe
  4. 4
    DéfiRespecter une dépendance et faire se chevaucher le reste
  5. 5
    ExplicationConserver chaque issue lorsque des résultats partiels restent utiles
  6. 6
    ExempleDistinguer premier acquittement et première réussite
  7. 7
    DéfiChoisir pour une page aux résultats partiels
  8. 8
    ConseilUn délai d’expiration arrête l’attente, pas l’opération
  9. 9
    DéfiQu’est-ce qui peut acquitter un groupe vide ?
  10. 10
    DéfiRelier le moment du lancement et la gestion des échecs
  11. 11
    RécapitulatifChoisir la règle relative aux issues

JavaScript asynchrone : QCM

40 Questions Pratiques en 4 séries

Série 1 : Suis le code des appels aux fonctions de rappel10 Questions Pratiques

Question 1 sur 10

Une page enregistre une minuterie, puis exécute un long calcul synchrone. La minuterie arrive à son terme pendant le calcul. Quand sa fonction de rappel peut-elle s’exécuter ?
  1. Dès que le délai demandé à la minuterie est écoulé.
  2. Pendant l’itération suivante de la boucle du calcul.
  3. Après que le calcul a libéré le thread principal.
  4. Sur un second thread créé par l’appel à la minuterie.
Afficher la réponseMasquer la réponse
Réponse : C
Le calcul conserve le thread principal jusqu’à sa fin : la fonction de rappel prête doit donc attendre. L’expiration du délai d’une minuterie ne peut pas interrompre le code JavaScript en cours d’exécution.

Question 2 sur 10

Dans quel ordre les résultats s’affichent-ils ?

console.log("open");
setTimeout(() => console.log("tick"), 0);
Promise.resolve().then(() => console.log("job"));
console.log("close");
  1. "open", "close", "job", "tick"
  2. "open", "tick", "job", "close"
  3. "open", "job", "close", "tick"
  4. "open", "close", "tick", "job"
Afficher la réponseMasquer la réponse
Réponse : A
Le script en cours affiche « open » et « close » avant l’exécution de toute fonction de rappel enregistrée. Son gestionnaire de promesse est une microtâche : il affiche donc « job » avant que la tâche de minuterie n’affiche « tick ». Le délai nul rend la minuterie prête à s’exécuter plus tard ; il ne la place pas avant le traitement des microtâches.

Question 3 sur 10

Une minuterie a été planifiée avec const reminder = setTimeout(showHint, 900);. Quelle instruction l’annule avant son exécution ?
  1. clearTimeout(showHint);
  2. setTimeout(reminder, 0);
  3. clearInterval(showHint);
  4. clearTimeout(reminder);
Afficher la réponseMasquer la réponse
Réponse : D
ClearTimeout identifie la minuterie par l’identifiant qu’elle a renvoyé, reminder. Passer showHint fournit la fonction, qui n’identifie pas cette minuterie planifiée.

Question 4 sur 10

Qu’affiche cette boucle après l’exécution de ses fonctions de rappel ?

for (var index = 2; index < 5; index++) {
  setTimeout(() => console.log(index), 0);
}
  1. 2, 3, 4
  2. 5, 5, 5
  3. 2, 2, 2
  4. 3, 4, 5
Afficher la réponseMasquer la réponse
Réponse : B
Les fonctions de rappel capturent toutes la même liaison var. Lorsqu’elles s’exécutent, la boucle s’est arrêtée avec index égal à 5 : les trois affichages lisent donc 5. La suite 2, 3, 4 apparaîtrait avec une liaison let distincte par itération, et non avec cette variable partagée.

Question 5 sur 10

Combien d’appels à la fonction de rappel sont terminés lorsque ce code atteint l’affichage ?

let calls = 0;
[3, 6, 9].map(n => {
  calls++;
  return n + 1;
});
console.log(calls);
  1. Trois appels sont terminés.
  2. Aucun appel n’est terminé.
  3. Un seul appel est terminé.
  4. Deux appels sont terminés.
Afficher la réponseMasquer la réponse
Réponse : A
Map invoque les trois fonctions de rappel avant de se terminer : calls vaut donc 3 lorsqu’il est affiché. Passer une fonction de rappel ne diffère pas son exécution lorsque l’API l’appelle de façon synchrone.

Question 6 sur 10

Que contient result lorsque l’affichage s’exécute ?

function make() {
  setTimeout(() => { return "badge"; }, 0);
}
const result = make();
console.log(result);
  1. La chaîne "badge".
  2. Une promesse tenue avec "badge".
  3. undefined
  4. La fonction de rappel de la minuterie.
Afficher la réponseMasquer la réponse
Réponse : C
Make ne contient aucune instruction de retour et renvoie undefined. Le retour ultérieur ne termine que la fonction de rappel de la minuterie ; il ne peut pas fournir une valeur à un appel externe déjà terminé.

Question 7 sur 10

Une fonction de rappel avec erreur en premier reçoit un objet Error et aucun résultat en cas d’échec. Qu’est-ce qui empêche le code de réussite situé après cette vérification de lire un item absent ?

if (err) {
  console.log(err.message);
  // Add one statement here.
}
console.log(item.name);
  1. err = null;
  2. return;
  3. console.log(item);
  4. callback = null;
Afficher la réponseMasquer la réponse
Réponse : B
Le retour termine cette fonction de rappel après qu’elle a signalé l’erreur : la ligne item.name n’est donc pas atteinte en cas d’échec. Affecter null à err ne change que la variable locale ; cela ne crée pas de résultat de réussite. La branche d’erreur doit arrêter le traitement normal de la réussite lorsqu’aucun élément n’existe.

Question 8 sur 10

Dans quel ordre les résultats s’affichent-ils ?

Promise.resolve().then(() => {
  console.log("oak");
  queueMicrotask(() => console.log("elm"));
}).then(() => console.log("ash"));
queueMicrotask(() => console.log("fir"));
console.log("pine");
  1. "pine", "oak", "elm", "ash", "fir"
  2. "pine", "fir", "oak", "elm", "ash"
  3. "pine", "oak", "fir", "ash", "elm"
  4. "pine", "oak", "fir", "elm", "ash"
Afficher la réponseMasquer la réponse
Réponse : D
Le script affiche « pine » et place d’abord oak dans la file avant fir. Le gestionnaire de oak ajoute elm, puis son retour rend prêt le gestionnaire ash de la chaîne : les deux rejoignent donc la file derrière fir, dans cet ordre. Ash ne peut pas précéder elm, car elm a été placé dans la file pendant l’exécution du gestionnaire, avant que la promesse renvoyée ne soit tenue.

Question 9 sur 10

Une opération qui produit un seul résultat utilise ce corps de minuterie. Que se passe-t-il lorsque id vaut 0 et quelle modification corrige le problème ?

if (id <= 0) callback(new Error("Invalid"));
callback(null, { id });
  1. Elle appelle une fois ; déplace l’appel de réussite avant la vérification.
  2. Elle appelle deux fois ; retire l’argument d’erreur du premier appel.
  3. Elle appelle deux fois ; termine la fonction après avoir signalé l’erreur.
  4. Elle appelle une fois ; ajoute un retour après l’appel de réussite.
Afficher la réponseMasquer la réponse
Réponse : C
La condition d’échec déclenche le premier appel de la fonction de rappel, mais aucune instruction de contrôle n’arrête le second appel. Un retour dans la branche d’échec empêche la poursuite jusqu’au second appel et préserve le contrat d’un seul résultat. Revenir après l’appel de réussite est trop tard, car les deux appels ont déjà eu lieu.

Question 10 sur 10

Dans quel ordre les résultats s’affichent-ils ?

console.log("outside");
const p = new Promise(resolve => {
  console.log("executor");
  resolve("value");
});
p.then(console.log);
console.log("registered");
  1. "outside", "executor", "registered", "value"
  2. "outside", "registered", "executor", "value"
  3. "outside", "executor", "value", "registered"
  4. "executor", "outside", "registered", "value"
Afficher la réponseMasquer la réponse
Réponse : A
Le constructeur Promise exécute sa fonction exécutrice pendant la construction, entre les deux affichages synchrones qui l’entourent. Le gestionnaire then s’exécute plus tard comme microtâche et affiche « value » en dernier. Tenir immédiatement la promesse ne rend pas synchrone l’exécution d’un gestionnaire enregistré avec then.
Série 2 : Transmets des valeurs avec les promesses et await10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Quelle valeur cette promesse fournit-elle à son gestionnaire de réussite ?

const p = new Promise((resolve, reject) => {
  resolve(14);
  reject(new Error("Changed"));
  resolve(28);
});
  1. 28
  2. 14
  3. L’objet Error avec le message "Changed".
  4. undefined
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Qu’affiche la console ?

const p = Promise.resolve(7);
p.then(n => n + 4);
p.then(n => console.log(n));
  1. 11
  2. undefined
  3. Un objet promesse.
  4. 7
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Qu’affiche la console ?

Promise.resolve(6)
  .then(n => n - 2)
  .then(n => n * 5)
  .then(console.log);
  1. 20
  2. 30
  3. 4
  4. undefined
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

La fonction wait(ms) renvoie une promesse tenue après environ ms millisecondes. Que reçoit console.log et quand ?

wait(120)
  .then(() => { wait(480).then(() => "ready"); })
  .then(console.log);
  1. "ready" après environ 600 ms.
  2. undefined après environ 600 ms.
  3. undefined après environ 120 ms.
  4. "ready" après environ 480 ms.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Quel type de valeur l’appel de cette fonction renvoie-t-il ?

async function count() { return 9; }
  1. Le nombre 9 directement.
  2. Une promesse tenue avec undefined.
  3. Une fonction qui renverra 9.
  4. Une promesse tenue avec 9.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Dans quel ordre les résultats s’affichent-ils ?

async function show() {
  console.log("inside");
  await 0;
  console.log("after await");
}
show();
console.log("caller");
  1. "caller", "inside", "after await"
  2. "inside", "caller", "after await"
  3. "inside", "after await", "caller"
  4. "caller", "after await", "inside"
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Une API à fonction de rappel appelle done(err, value) une fois. Que doit faire la fonction enveloppante renvoyant une promesse lorsque err est un objet Error ?
  1. Appeler resolve avec err et arrêter cette fonction de rappel.
  2. Lever err après le retour de la fonction de rappel différée.
  3. Appeler reject avec err et arrêter cette fonction de rappel.
  4. Appeler resolve avec value, puis reject avec err.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Qu’affiche la console ?

async function permitted() { return false; }
if (permitted()) console.log("enter");
else console.log("stop");
  1. "enter"
  2. "stop"
  3. false
  4. Rien avant l’acquittement de la promesse.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

record(id) renvoie une promesse et peut être rejetée. Comment cette fonction doit-elle traiter les identifiants dans l’ordre, s’arrêter en cas d’échec et permettre au code appelant d’intercepter cet échec ?

async function saveAll(ids) {
  ids.forEach(async id => { await record(id); });
}
  1. Attendre l’appel forEach existant dans la fonction.
  2. Retirer await de record dans la fonction de rappel asynchrone existante.
  3. Utiliser map avec des fonctions de rappel asynchrones, mais ignorer le tableau renvoyé.
  4. Remplacer forEach par for...of et attendre record dans la boucle.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Quelle valeur le dernier gestionnaire affiche-t-il ?

Promise.resolve(11)
  .finally(() => 40)
  .then(n => n + 2)
  .finally(() => Promise.resolve(90))
  .then(console.log);
  1. 42
  2. 13
  3. 90
  4. undefined
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 3 : Gère les échecs et combine des tâches indépendantes10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Un gestionnaire catch renvoie "default" après avoir reçu un rejet. Que reçoit le gestionnaire then suivant ?
  1. La raison initiale du rejet.
  2. Une valeur undefined malgré le retour.
  3. Une promesse rejetée contenant "default".
  4. La valeur de réussite "default".
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Qu’affiche la console ?

Promise.resolve("start")
  .then(() => { throw new Error("later"); },
        () => console.log("same call"))
  .catch(err => console.log(err.message));
  1. "same call" seulement.
  2. "later" seulement.
  3. "same call", puis "later".
  4. "start", puis "later".
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Dans quel ordre les résultats s’affichent-ils ?

async function run() {
  try {
    await Promise.reject(new Error("busy"));
    console.log("saved");
  } catch (err) {
    console.log(err.message);
  } finally {
    console.log("reset");
  }
}
run();
  1. "saved", "reset"
  2. "reset", "busy"
  3. "busy", "reset"
  4. "busy", "saved", "reset"
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Qu’affiche le code appelant ?

async function read() {
  try {
    return Promise.reject(new Error("missing"));
  } catch {
    return "local";
  }
}
read().then(console.log).catch(err => console.log(err.message));
  1. "missing"
  2. "local"
  3. undefined
  4. Rien, car la fonction reste en attente.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une fonction encapsule une erreur sous la forme new Error("Report failed", { cause: original }). Quelle propriété garde l’objet Error initial disponible ?
  1. message
  2. name
  3. cause
  4. status
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Une fonction utilitaire de nouvelle tentative attend une nouvelle tâche dans try, revient en cas de réussite et réessaie dans catch jusqu’à sa limite de quatre appels. La tâche est rejetée aux appels 1 et 2, puis tenue avec "ok" à l’appel 3. Que se passe-t-il ?
  1. Elle effectue quatre appels et sa promesse est tenue avec "ok".
  2. Elle effectue un appel et sa promesse est rejetée avec la première erreur.
  3. Elle effectue trois appels et sa promesse est rejetée avec la deuxième erreur.
  4. Elle effectue trois appels et sa promesse est tenue avec "ok".
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Deux fonctions indépendantes fondées sur des minuteries prennent environ 350 ms et 900 ms. Toutes deux sont appelées dans le tableau d’entrée de await Promise.all(...) et réussissent. Combien de temps dure environ l’attente combinée ?
  1. Environ 900 ms.
  2. Environ 1 250 ms.
  3. Environ 350 ms.
  4. Environ 550 ms.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Des tâches sont lancées ensemble : A est tenue après 800 ms, B est rejetée après 250 ms et C produit un affichage comme effet de bord et est tenue après 600 ms. Que fait Promise.all([A, B, C]) ?
  1. Elle est rejetée vers 800 ms ; C peut encore afficher son message vers 600 ms.
  2. Elle est rejetée vers 250 ms ; C peut encore afficher son message vers 600 ms.
  3. Elle est rejetée vers 250 ms ; C est annulée avant son affichage.
  4. Elle est tenue vers 800 ms avec A et C, mais sans résultat pour B.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Des panneaux indépendants doivent chacun afficher leur résultat ou leur propre erreur une fois toutes les tentatives terminées. Quel combinateur de promesses fournit les objets de résultat nécessaires ?
  1. Promise.allSettled
  2. Promise.all
  3. Promise.race
  4. Promise.any
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Deux promesses commencent ensemble : l’une est rejetée après environ 150 ms et l’autre est tenue avec "backup" après environ 400 ms. Quelle différence y a-t-il entre race et any ?
  1. Race est tenue vers 400 ms ; any est rejetée vers 150 ms.
  2. Les deux sont rejetées vers 150 ms avec le premier échec.
  3. Race est rejetée vers 150 ms ; any est tenue vers 400 ms.
  4. Les deux sont tenues vers 400 ms avec la valeur de secours.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 4 : Débogue des déroulements asynchrones complets10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Qu’est-ce qui s’exécute en premier lors de l’évaluation de cette instruction ?

setTimeout(showMessage(), 500);
  1. L’appel à showMessage s’exécute immédiatement.
  2. La minuterie attend 500 ms avant showMessage.
  3. La minuterie place showMessage dans la file comme microtâche.
  4. Une promesse en attente doit d’abord s’acquitter.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une fonction enveloppante asynchrone lance une opération avec une fonction de rappel suivant la convention de l’erreur en premier, mais ne renvoie jamais de promesse reliée à cette fonction de rappel. Son corps atteint immédiatement sa fin. Que donne l’attente de la fonction enveloppante ?
  1. La valeur de réussite future de la fonction de rappel.
  2. L’objet Error futur de la fonction de rappel.
  3. Undefined avant que le résultat de la fonction de rappel soit prêt.
  4. Une attente jusqu’à l’appel de la fonction de rappel.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

inner est encore en attente. Que se passe-t-il ici si inner est rejetée plus tard ?

const outer = new Promise((resolve, reject) => {
  resolve(inner);
  reject(new Error("replacement"));
});
outer.catch(err => console.log(err.message));
  1. Outer est immédiatement rejetée avec "replacement".
  2. Outer suit la raison du rejet de inner.
  3. Outer est tenue avec l’objet promesse inner.
  4. Outer reste en attente après le rejet de inner.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Dans quel ordre les résultats s’affichent-ils ?

async function step() {
  console.log("a");
  await null;
  console.log("b");
  queueMicrotask(() => console.log("c"));
}
setTimeout(() => console.log("d"), 0);
step();
Promise.resolve().then(() => console.log("e"));
console.log("f");
  1. "a", "f", "e", "b", "c", "d"
  2. "a", "f", "b", "c", "e", "d"
  3. "a", "b", "f", "e", "c", "d"
  4. "a", "f", "b", "e", "c", "d"
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Qu’affiche le dernier gestionnaire ?

Promise.reject(new Error("first"))
  .catch(() => 4)
  .then(n => { throw new Error("second " + n); })
  .finally(() => 9)
  .catch(err => console.log(err.message));
  1. "first"
  2. "second 4"
  3. 9
  4. "second 9"
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Un appel qui récupère un compte prend environ 200 ms. Une fois sa promesse tenue, deux appels indépendants fondés sur ce compte prennent environ 500 ms et 800 ms. Ils ont tous deux besoin de ce compte et tous les résultats sont nécessaires. Quel plan fournit le résultat complet le plus tôt ?
  1. Attendre le compte, puis lancer les deux appels suivants avec Promise.all ; environ 1 000 ms.
  2. Lancer immédiatement les trois appels dans Promise.all ; environ 800 ms.
  3. Attendre le compte, puis attendre chaque appel suivant à tour de rôle ; environ 1500 ms.
  4. Attendre le compte, puis mettre les appels suivants en concurrence ; environ 700 ms.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Pourquoi cette fonction de nouvelle tentative ne réessaie-t-elle pas une tâche rejetée de façon asynchrone ?

async function retry(task) {
  for (let n = 0; n < 3; n++) {
    try { return task(); }
    catch (err) { if (n === 2) throw err; }
  }
}
  1. Elle intercepte le rejet mais s’arrête parce que la boucle commence à zéro.
  2. Elle ne peut pas réessayer car task est passée comme fonction plutôt que comme promesse.
  3. Elle effectue les trois tentatives avant l’acquittement de toute promesse renvoyée.
  4. Elle renvoie la promesse avant que son rejet puisse atteindre le catch local.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Quel est l’état de Promise.race([]) lorsqu’aucune entrée ne sera jamais ajoutée ?
  1. Elle est tenue avec [].
  2. Elle est rejetée immédiatement.
  3. Elle reste en attente.
  4. Elle se résout en undefined.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Deux tentatives commencent ensemble. La seconde entrée est rejetée en premier ; la première entrée est rejetée plus tard. Que fournit finalement Promise.any([first, second]) à catch ?
  1. L’objet Error de la seconde entrée dès son rejet.
  2. Une AggregateError avec les raisons dans l’ordre première, puis seconde.
  3. Une AggregateError avec les raisons dans l’ordre seconde, puis première.
  4. L’objet Error de la première entrée seul après le rejet ultérieur.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Qu’affiche le code appelant ?

async function value() {
  try {
    return await Promise.reject(new Error("lost"));
  } catch {
    return "fallback";
  } finally {
    console.log("cleanup");
  }
}
value().then(console.log);
console.log("caller");
  1. "cleanup", "caller", "fallback"
  2. "caller", "fallback", "cleanup"
  3. "caller", "cleanup", "lost"
  4. "caller", "cleanup", "fallback"
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Tu bloques sur ton propre exercice ? Aide aux Devoirs

Mots-Clés

72 Mots-Clés, chacun avec sa définition

A

Abonnement à une promesse
Un abonnement à une promesse enregistre un gestionnaire sur une promesse donnée.
Deux gestionnaires associés à une promesse tenue reçoivent chacun son nombre initial, même lorsque l’un d’eux renvoie un nombre modifié.
Acquittée
Une promesse acquittée a été tenue ou rejetée : son état et son issue sont alors fixés.
Appeler à nouveau resolve après qu’une promesse a été tenue ne remplace pas la valeur reçue par ses gestionnaires.
Adoption d’une promesse
L’adoption d’une promesse fait suivre à une promesse la valeur de réussite ou la raison de rejet future d’une autre promesse, au lieu de traiter cette dernière comme un objet ordinaire.
Renvoyer une promesse depuis then fait attendre le gestionnaire suivant, qui reçoit sa valeur sans promesse imbriquée supplémentaire.
AggregateError
Une AggregateError regroupe plusieurs erreurs ; Promise.any l’utilise avec un tableau errors ordonné selon les entrées lorsque toutes les tentatives échouent.
Lorsque deux tentatives échouent dans l’ordre inverse, le tableau errors énumère toujours leurs raisons dans l’ordre initial des entrées.
Anti-rebond
L’anti-rebond redémarre une minuterie à chaque événement pour qu’une action attende une période sans activité.
La saisie rapide de plusieurs caractères remplace chaque fois la minuterie en attente, ne laissant qu’une mise à jour après l’arrêt de la saisie.
Await au niveau supérieur
Await au niveau supérieur désigne await utilisé directement dans le corps d’un module JavaScript, où le langage l’autorise hors d’une fonction asynchrone.
Un module peut attendre directement son initialisation, tandis qu’une fonction ordinaire a toujours besoin de son propre mot-clé async.

B

Bloc finally
Un bloc finally s’exécute lorsque le contrôle quitte sa structure try/catch et permet le nettoyage après une réussite, un échec ou une instruction return.
Un bouton est réactivé dans finally afin que l’interface soit prête pour une autre action après une tentative réussie ou échouée.
Bloc try
Un bloc try protège les instructions dont les exceptions peuvent transmettre le contrôle au catch qui lui est associé.
Attendre une opération de préparation dans try permet à la fonction qui l’englobe de récupérer si cette opération est rejetée plus tard.
Blocage
Le blocage consiste à occuper un thread avec une opération, empêchant d’autres instructions planifiées de s’y exécuter.
Une boucle qui occupe le thread peut retarder une minuterie dont le délai est nul, car la fonction de rappel a toujours besoin du thread principal occupé.
Boucle d’événements
La boucle d’événements coordonne les tâches, les points de contrôle des microtâches et les occasions de rendu afin que les opérations prêtes puissent s’exécuter de façon ordonnée.
Suivre d’abord un script, puis ses microtâches explique pourquoi son message de promesse apparaît avant son message de minuterie.

C

Cause de l’erreur
La cause de l’erreur est un échec initial conservé dans la propriété cause d’un nouvel objet Error.
Une erreur externe qui indique « Report failed » contient toujours, dans sa cause, l’erreur d’appareil qui a empêché la préparation du rapport.
Chaîne de promesses
Une chaîne de promesses relie des gestionnaires par les promesses renvoyées et transmet chaque valeur renvoyée ou issue asynchrone adoptée au maillon suivant.
Un gestionnaire renvoie une promesse de préparation afin que le gestionnaire suivant reçoive l’élément terminé après la préparation.
Chaîne sans imbrication
Une chaîne sans imbrication exprime des étapes de promesses dépendantes sous forme de gestionnaires successifs au niveau externe, en gardant leurs délais et la propagation des erreurs reliés.
Renvoyer chaque nouvelle opération permet à un seul catch final de recevoir les échecs des étapes reliées qui le précèdent.
Code synchrone
Le code synchrone termine chaque instruction avant de passer à la suivante.
Une longue boucle retarde l’affichage suivant, car chaque itération s’exécute avant que le contrôle puisse quitter la boucle.
Concurrence
La concurrence permet à des opérations indépendantes de rester en cours pendant des attentes qui se chevauchent, tandis que leurs gestionnaires JavaScript s’exécutent toujours un par un.
Deux minuteries commencent ensemble : le code appelant attend donc environ la durée de la plus lente au lieu d’additionner les deux délais.
Continuation
Une continuation est le code d’une fonction asynchrone qui reprend après un await.
Même attendre un nombre ordinaire reporte les lignes restantes au lieu de les exécuter avant la reprise du code appelant.

E

En attente
L’état en attente est l’état d’une promesse avant qu’elle soit tenue ou rejetée.
Une pause fondée sur une minuterie reste en attente pendant que l’environnement attend d’appeler la fonction qui la résout.
Enfer des fonctions de rappel
L’enfer des fonctions de rappel est un code à fonctions de rappel profondément imbriquées dans lequel chaque étape dépendante ajoute un niveau et souvent une branche de gestion des erreurs.
Lire un profil, puis des projets, puis des tâches crée plusieurs fonctions de rappel imbriquées difficiles à parcourir.
Environnement hôte
L’environnement hôte est le navigateur ou l’environnement d’exécution Node.js qui fournit des fonctionnalités comme les minuteries et gère leur planification.
Le navigateur suit le délai d’une minuterie, puis met sa fonction de rappel à disposition pour que JavaScript l’exécute plus tard.
Erreur passée sous silence
Une erreur passée sous silence est un échec intercepté puis masqué sans signalement utile ni propagation, ce qui rend l’action échouée plus difficile à diagnostiquer.
Un catch vide autour d’une opération d’enregistrement laisse la page silencieuse alors que l’enregistrement n’a pas réussi.
Exécution jusqu’à achèvement
L’exécution jusqu’à achèvement signifie qu’une fois une tâche ou une microtâche commencée, les fonctions de rappel placées dans une file de façon asynchrone ne peuvent pas interrompre son code en cours.
Une minuterie qui arrive à son terme au milieu d’une boucle n’insère pas sa fonction de rappel entre les instructions de cette boucle.

É

Échec immédiat
L’échec immédiat rejette une attente combinée dès qu’une entrée nécessaire échoue, sans attendre la fin des autres entrées.
Une préparation groupée échoue lorsqu’une partie échoue après 200 ms, alors qu’une autre travaille encore en vue de son achèvement ultérieur.
Événement d’erreur
Un événement d’erreur signale un échec par un gestionnaire d’événements, ce qui permet à une API de navigateur d’utiliser un chemin d’échec distinct de son événement de réussite.
Le gestionnaire d’échec d’une image est affecté avant que sa source commence à se charger, aux côtés de son gestionnaire de réussite.

F

Famine due aux microtâches
La famine due aux microtâches retarde les tâches et le rendu parce que le traitement de la file de microtâches ne se termine jamais.
Une microtâche qui ajoute toujours une autre copie d’elle-même à la file peut empêcher indéfiniment un gestionnaire de clic de s’exécuter.
Fonction asynchrone
Une fonction asynchrone renvoie toujours une promesse correspondant à son résultat de retour ou à l’erreur qu’elle lève.
Appeler une fonction asynchrone qui renvoie un nombre donne une promesse au code appelant, même sans await dans son corps.
Fonction de rappel
Une fonction de rappel est une fonction passée à une autre fonction pour que celle-ci l’appelle.
Passer un gestionnaire nommé fournit une action ; ajouter des parenthèses l’appellerait pendant l’évaluation de l’argument.
Fonction de rappel asynchrone
Une fonction de rappel asynchrone est appelée plus tard par un mécanisme de planification, après le retour au code appelant de l’opération qui l’a enregistrée.
Une fonction de préparation de libellé se termine d’abord ; sa fonction de rappel de résultat reçoit plus tard le libellé terminé.
Fonction de rappel avec erreur en premier
Une fonction de rappel avec erreur en premier reçoit un argument d’erreur avant son résultat : null en cas de réussite et un objet Error en cas d’échec.
Le code appelant vérifie l’erreur avant de lire l’élément, afin qu’une opération échouée ne déclenche pas le traitement de réussite.
Fonction de rappel de finally
Une fonction de rappel de finally s’exécute après l’une ou l’autre issue d’une promesse, ne reçoit aucun argument et conserve normalement la valeur ou la raison précédente.
La fonction de rappel masque un indicateur de chargement après une réussite ou un échec ; une exception pendant ce nettoyage deviendrait un nouvel échec.
Fonction de rappel synchrone
Une fonction de rappel synchrone est appelée avant le retour de la fonction qui la reçoit : son travail a donc lieu pendant l’appel en cours de cette fonction.
La fonction de rappel passée à map double chaque élément avant que le tableau de résultats complet soit renvoyé.
Fonction enveloppante renvoyant une promesse
Une fonction enveloppante renvoyant une promesse expose l’issue d’une autre API par une promesse renvoyée, permettant au code appelant d’utiliser le résultat avec des gestionnaires ou await.
Encapsuler une minuterie crée une pause réutilisable dont l’achèvement est relié à la promesse renvoyée au code appelant.
Fonction exécutrice
Une fonction exécutrice est la fonction que le constructeur Promise appelle immédiatement avec resolve et reject.
La fonction exécutrice enregistre immédiatement une minuterie ; le gestionnaire de réussite s’exécute toujours plus tard par la file de microtâches.

G

Gestionnaire de rejet
Un gestionnaire de rejet reçoit la raison de l’échec d’une promesse et peut récupérer avec une valeur ou préserver l’échec en levant une erreur.
Un gestionnaire catch fournit des paramètres par défaut lorsqu’une opération de chargement des paramètres échouée ne doit pas arrêter l’action globale.
Gestionnaire de réussite
Un gestionnaire de réussite est une fonction enregistrée avec then qui reçoit la valeur de réussite d’une promesse et détermine l’issue d’une nouvelle promesse.
Un gestionnaire multiplie le nombre reçu et renvoie le nouveau nombre au maillon suivant de la chaîne.

I

Identifiant de minuterie
Un identifiant de minuterie désigne une minuterie planifiée afin que le programme puisse l’annuler.
Conserver l’identifiant renvoyé permet à l’événement de saisie suivant d’annuler la mise à jour de suggestion précédente en attente.

L

Levée d’exception
Une levée d’exception interrompt l’exécution normale à cet endroit et transmet une erreur à un catch applicable, ou la propage vers l’extérieur si aucun ne s’applique.
Une promesse rejetée que l’on attend se comporte comme une levée d’exception à sa ligne await et fait ignorer les instructions restantes dans try.

M

Microtâche
Une microtâche est une opération placée dans une file, comme un gestionnaire de promesse, qui s’exécute à un point de contrôle des microtâches avant que la boucle d’événements ne commence une autre tâche.
Le gestionnaire d’une promesse tenue s’exécute après le script en cours, mais avant une tâche de minuterie prête dont le délai est nul.
Minuterie périodique
Une minuterie périodique planifie à répétition une fonction de rappel jusqu’à son annulation.
Un compteur annule sa minuterie périodique après la cinquième exécution pour que la page cesse de produire des messages supplémentaires.

N

Nouvelle tentative
Une nouvelle tentative lance un nouvel essai après un échec, généralement avec un délai et une limite finie de tentatives lorsque l’échec peut être temporaire.
Une tâche réussit à son troisième appel : une fonction utilitaire disposant de quatre tentatives revient donc sans effectuer de quatrième appel.

O

Objet Error
Un objet Error représente un échec avec un message et un nom, et contient généralement des informations de pile utiles pour localiser le problème.
Lire le message d’un objet Error intercepté et créé avec le message « Missing label » donne ce texte sans imposer à l’interface utilisateur d’afficher sa pile.
Opérateur await
L’opérateur await suspend sa fonction asynchrone jusqu’à ce qu’une issue soit disponible, en fournissant une valeur de réussite ou en levant la raison du rejet à cette ligne.
Attendre une pause laisse au code appelant la possibilité d’afficher un message avant que la fonction suspendue ne reprenne son instruction suivante.
Opération asynchrone
Une opération asynchrone commence maintenant et transmet son issue plus tard, tandis que d’autres instructions peuvent continuer.
Une minuterie est enregistrée maintenant, tandis que sa fonction de rappel affiche un message après que l’environnement a géré le délai.
Opération dépendante
Une opération dépendante a besoin du résultat d’une opération précédente et ne doit commencer qu’une fois cette entrée nécessaire disponible.
Une fonction de rappel reçoit un utilisateur, puis lance l’opération suivante avec cet utilisateur comme argument requis.
Opérations indépendantes
Des opérations indépendantes peuvent commencer sans les résultats les unes des autres, ce qui permet à leurs attentes de se chevaucher lorsque le programme les lance ensemble.
La préparation d’une couverture et celle d’un libellé peuvent se chevaucher lorsque toutes deux disposent déjà des données d’entrée nécessaires.
Ordre des entrées
L’ordre des entrées est la disposition des valeurs ou des promesses fournies à un combinateur.
La déstructuration du résultat de Promise.all nomme les valeurs selon leur place dans le tableau initial.
Oubli de await
Un oubli de await laisse une promesse là où le code attend sa valeur future, ce qui provoque des conditions ou des opérations numériques incorrectes.
Multiplier la promesse renvoyée par une fonction de quantité produit NaN au lieu de multiplier le nombre qu’elle fournira.
Oubli de return
Un oubli de return laisse le résultat d’un gestionnaire à undefined et peut détacher une opération qu’il devait renvoyer.
Un gestionnaire entre accolades lance une pause mais oublie de la renvoyer : le gestionnaire suivant s’exécute donc avant la fin de cette pause.

P

Périmètre d’interception des erreurs
Un périmètre d’interception des erreurs est l’ensemble des opérations reliées dont les échecs peuvent atteindre un gestionnaire catch donné, selon son emplacement et les appels attendus.
Un catch placé au milieu gère les étapes précédentes mais ne peut pas gérer une nouvelle erreur levée par un gestionnaire ultérieur.
Pile d’appels
La pile d’appels enregistre les appels de fonctions actifs, l’appel en cours se trouvant au sommet.
Si un gestionnaire appelle une fonction utilitaire, celle-ci s’exécute au sommet de la pile jusqu’à son retour au gestionnaire.
Promesse
Une promesse est un objet représentant une issue future unique, qui peut fournir une valeur ou une raison d’échec aux gestionnaires qui lui sont reliés.
Une fonction renvoie immédiatement une promesse, puis une minuterie fournit plus tard la valeur attendue par le code appelant.
Promesse de fonction de rappel ignorée
Une promesse de fonction de rappel ignorée est une promesse renvoyée par une fonction de rappel que l’API appelante n’utilise pas pour suivre l’achèvement ou l’échec.
La méthode forEach ignore la promesse d’une fonction de rappel asynchrone : la fonction qui l’englobe peut donc se terminer avant cette opération.
Promessification
La promessification adapte une API à fonctions de rappel en une API qui renvoie une promesse, en reliant la réussite et l’échec de la fonction de rappel à l’acquittement de cette promesse.
Une fonction enveloppante autour d’une API de libellé à fonction de rappel résout la promesse avec le libellé ou la rejette avec l’erreur, afin qu’un appelant asynchrone puisse attendre la fin de l’opération.
Promise.all
Promise.all combine les promesses d’entrée en une seule promesse de toutes les valeurs de réussite dans l’ordre des entrées, rejetée au premier rejet d’une entrée.
La première entrée, plus lente, reste première dans le tableau de résultats même si la seconde se termine plus tôt.
Promise.allSettled
Promise.allSettled attend chaque entrée et est tenue avec des objets de résultat dans l’ordre des entrées, décrivant chaque valeur de réussite ou raison de rejet.
Une page conserve un panneau qui a réussi et affiche une erreur pour un panneau qui a échoué après avoir examiné les deux objets de résultat.
Promise.any
Promise.any est tenue avec la première valeur de réussite d’une entrée et n’est rejetée avec une AggregateError que lorsque toutes les entrées ont été rejetées.
Une tentative échouée précocement est ignorée tant qu’une autre tentative a encore une chance de fournir un résultat utilisable.
Promise.race
Promise.race suit la première entrée acquittée et prend sa valeur de réussite ou sa raison de rejet comme issue combinée.
Un délai d’expiration qui rejette l’emporte sur une opération réussie plus lente, tandis que cette opération continue de s’exécuter.
Propagation des rejets
La propagation des rejets transmet l’échec entre les maillons reliés d’une chaîne de promesses, en ignorant les gestionnaires de réussite jusqu’à ce qu’un gestionnaire de rejet le traite.
Une erreur levée à la deuxième étape atteint le catch final sans exécuter le gestionnaire de réussite de la troisième étape.

R

Récupération après erreur
La récupération après erreur transforme le chemin échoué d’une promesse en chemin réussi en renvoyant une valeur utilisable ou une promesse tenue depuis un gestionnaire de rejet.
Renvoyer un libellé par défaut dans catch donne au gestionnaire de réussite suivant une valeur qu’il peut utiliser pour continuer.
Rejet non géré
Un rejet non géré est le rejet d’une promesse qui n’a toujours pas de gestionnaire de rejet lorsque l’hôte vérifie les rejets non gérés.
Une action en arrière-plan lancée sans catch peut être rejetée après la reprise du code appelant, laissant son échec non géré.
Rejetée
L’état rejetée est l’état acquitté d’une promesse qui contient une raison d’échec.
Une vérification de stock échouée rejette la promesse avec un objet Error dont le message explique pourquoi la quantité demandée n’est pas disponible.
Relancer une exception
Relancer une exception consiste à lever à nouveau une erreur interceptée pour qu’un gestionnaire ultérieur puisse la recevoir.
Un catch de niveau inférieur consigne une erreur et la relance, laissant à l’action externe la responsabilité du message destiné à l’utilisateur.
Résolue
Une promesse résolue a une issue définitivement déterminée, éventuellement par l’adoption d’une autre promesse encore en attente qui peut être rejetée plus tard.
Résoudre une promesse enveloppante avec une promesse en attente lui fait suivre la réussite ou l’échec ultérieur de cette dernière.
Résultat intermédiaire
Un résultat intermédiaire est une valeur produite pendant une séquence et utilisée par une étape ultérieure.
Une fonction asynchrone stocke l’utilisateur puis les commandes, et garde les deux valeurs locales disponibles pour le message final.
Retour anticipé
Un retour anticipé termine une fonction avant l’exécution de ses instructions restantes.
Revenir après avoir consigné une erreur de fonction de rappel empêche la ligne suivante de lire le nom d’un résultat absent.

S

Solution de repli
Une solution de repli est une valeur ou un comportement de remplacement utilisé après un échec lorsque l’action globale peut encore effectuer un travail utile sans son résultat initial.
En l’absence d’un paramètre de thème facultatif, un thème clair sert de solution de repli tandis que le reste de la page continue de se charger.

T

Tâche
Une tâche est une unité de travail planifiée, comme un script, un gestionnaire d’événements ou une fonction de rappel de minuterie.
Le navigateur termine le script en cours avant de lancer une fonction de rappel de minuterie devenue prête.
Temporisation
Une temporisation est une fonction de rappel planifiée pour une seule exécution, qui peut s’exécuter après un délai ; son exécution effective dépend aussi de la planification.
Une indication planifiée après 600 ms peut apparaître plus tard si le thread principal effectue encore d’autres opérations à ce moment-là.
Temporisation imbriquée
Une temporisation imbriquée planifie une autre temporisation depuis une fonction de rappel de minuterie, ce qui permet au délai suivant de commencer après le travail de l’exécution en cours.
Une vérification de progression ne planifie sa prochaine temporisation qu’après la fin de sa vérification synchrone en cours.
Tenue
L’état tenue est l’état acquitté d’une promesse qui contient une valeur de réussite.
Une vérification de quantité réussie tient la promesse avec le nombre restant, que son gestionnaire de réussite reçoit.
Thread principal
Le thread principal exécute le JavaScript ordinaire de la page et les opérations liées à l’écran.
Un long calcul sur le thread principal empêche un gestionnaire de clic prêt de s’exécuter jusqu’à la fin du calcul.
Traitement séquentiel
Le traitement séquentiel lance chaque étape asynchrone après l’achèvement de la précédente, en respectant les dépendances ou un ordre d’opérations requis.
Une boucle for...of attend une opération d’enregistrement avant de lancer la suivante et affiche la fin après la dernière réussite.

V

Valeur vraie
Une valeur vraie est traitée comme vraie dans une condition ; une promesse est une valeur vraie parce qu’elle est un objet, quel que soit son résultat futur.
Une promesse tenue avec false fait tout de même entrer dans une branche if lorsque le code teste directement l’objet promesse.

À propos de cette unité

Par StudeliSignaler une erreur

Crée ton propre Matériel d'Étude

Transforme tes notes, diapos et documents en Guides d'Étude, Questions Pratiques, Flashcards et 6 autres outils.

Commencer