web-dev-qa-db-fra.com

Quand le corps d'une promesse est-il exécuté?

Supposons que j'ai la Promise suivante:

function doSomethingAsynchronous() {
  return new Promise((resolve) => {
    const result = doSomeWork();

    setTimeout(() => {
      resolve(result);
   }), 100);
  });
}

À quel moment dans le temps doSomeWork() est-il appelé? Est-ce juste après ou lorsque la Promise est construite? Sinon, y a-t-il quelque chose de supplémentaire que je dois faire explicitement pour m'assurer que le corps de Promise est exécuté?

28
Kevin

Immédiatement, oui, par spécification.

De le MDN :

La fonction exécuteur est exécutée immédiatement par l'implémentation Promise, transmettant les fonctions de résolution et de rejet (l'exécuteur est appelé avant même que le constructeur Promise ne retourne l'objet créé).

La voici dans la spécification ECMAScript (bien sûr plus difficile à lire ...): http://www.ecma-international.org/ecma-262/6.0/#sec-promise-executor

Cette garantie peut être importante. Par exemple, lorsque vous préparez plusieurs promesses, vous passez ensuite à all ou race, ou lorsque vos exécuteurs ont des effets secondaires synchrones.

30
Denys Séguret

Oui, lorsque vous construisez une promesse, le premier paramètre est exécuté immédiatement.

En général, vous n'utiliseriez pas vraiment une promesse de la même manière, car avec votre implémentation actuelle, elle serait toujours synchrone.

Vous préférez l'implémenter avec un délai d'expiration ou appelez la fonction de résolution dans le cadre d'un rappel ajax

function doSomethingAsynchronous() {
  return new Promise((resolve) => {
    setTimeout(function() {
      const result = doSomeWork();
      resolve(result);
    }, 0);
  });
}

La méthode setTimeout appelle ensuite la fonction au prochain instant possible où la file d'attente d'événements est libre.

4
Icepickle

Vous pouvez voir ci-dessous que le corps est exécuté immédiatement en insérant du code synchrone dans le corps plutôt qu'en mode asynchrone:

function doSomethingAsynchronous() {
  return new Promise((resolve) => {
    console.log("a");
    resolve("promise result");
  });
}
doSomethingAsynchronous();console.log("b");

Le résultat montre que le corps de la promesse est exécuté immédiatement (avant que «b» ne soit imprimé):

a
b

Le résultat de la promesse est conservé, pour être communiqué à un appel 'alors' par exemple:

doSomethingAsynchronous().then(function(pr){console.log("c:"+pr);});console.log("b");

Résultat:

a
b
c:promise result

Même affaire avec le code asynchrone dans le corps, sauf le délai indéterminé avant que la promesse soit remplie et que «then» peut être appelé (point «c»). Donc 'a' et 'b' seraient imprimés dès que doSomethingAsynchronous() reviendra, mais 'c' n'apparaîtra que lorsque la promesse sera remplie ('résoudre' est appelé).

Ce qui semble étrange en surface, une fois l’appel à "then" ajouté, c’est que "b" est imprimé avant "c" même lorsque tout est synchrone. Sûrement, 'a' imprimerait, puis 'c' et enfin 'b'? La raison pour laquelle "a", "b" et "c" sont imprimés dans cet ordre est que, peu importe si le code contenu dans le corps est asynchrone ou sync, la méthode "then" est toujours appelée de manière asynchrone par la promesse. Dans mon esprit, j'imagine que la méthode 'then' est invoquée par quelque chose comme setTimeout(function(){then(pr);},0); dans la promesse une fois que le mot 'résoudre' est appelé. C'est à dire. le chemin d'exécution en cours doit être terminé avant que la fonction transmise à 'then' soit exécutée. Pas évident de la spécification Promise pourquoi il fait cela. Je suppose que cela garantit un comportement cohérent en ce qui concerne le moment où "then" est appelé (toujours après la fin du thread d'exécution en cours), ce qui est censé permettre à plusieurs promesses d'être empilées/chaînées ensemble avant de lancer tous les appels "then" successivement.

0
Moika Turns