Supposons que nous ayons une promesse dans une fonction asynchrone:

(async function() {

  let x = 0;

  await new Promise((resolve, reject) => {
    setTimeout(() => resolve(), 2000)
  })
  .then(res => {
    x = 100;
  })

  console.log(x);
})();

La sortie de la console est toujours 100, et jamais 0. Je l'ai essayé dans tous les principaux navigateurs et Node.js. C'est exactement ce que je voulais voir, mais je sens l'odeur du code autour de lui. Je ne sais pas si c'est un moyen sûr de transmettre une valeur à x. Cela semble fonctionner, même si je mets beaucoup de code avant cela. À moins que ce ne soit quelque chose d'asynchrone (comme un autre setTimeout()), tout va bien.

Quelqu'un peut-il confirmer si la branche .then() est réellement prioritaire et s'exécute avant la ligne alert(x), ou cela se produit-il uniquement par hasard?

(Oui, je sais qu'il existe de meilleures façons de le faire, mais il s'agit d'un extrait de code de démonstration simplifié.)

1
Tamás Polgár 30 août 2020 à 03:05

2 réponses

Meilleure réponse

C'est garanti car le await se bloque jusqu'à ce que la chaîne de promesses se termine. En effet, le .then enchaîné à la promesse d'origine renvoie une nouvelle promesse, et le await opère sur cela.

Le comportement attendu est que console.log se produit ~ 2 s à partir du moment où la fonction commence à s'exécuter (lorsque la promesse est résolue), après que x est déjà affecté (dans le cadre de la chaîne de promesse).

Pour «odeur de code» - je dirais qu'il est plus propre de renvoyer l'état des promesses et d'éviter les effets secondaires. Cependant, étant donné la portée limitée et l'ordre d'exécution garanti.

2
user2864740 30 août 2020 à 00:20

Oui, cette méthode est "sûre". Vous await explicitement la promesse que le bloc de code .then () renvoie. Si votre promesse est rejetée (échec de la demande réseau par exemple), votre code sera rompu, alors assurez-vous d'ajouter un .catch (erreur) à la fin.

Btw, une manière plus concise d'écrire ce code serait comme ceci:

(async function() {
  let x = 0;

  await new Promise((resolve, reject) => {
    setTimeout(() => resolve(), 2000)
  });

  x = 100;
  console.log(x);
})();

Si vous n'avez pas besoin d'une valeur de retour de la promesse, ce code agit exactement de la même manière que le vôtre.

EDIT: Puisque la promesse DEVRAIT en effet fournir la valeur, vous pouvez la réécrire comme:

(async function() {
  let x = 0;

  const res = await new Promise((resolve, reject) => {
    setTimeout(() => resolve(100), 2000)
  });

  x = res;
  console.log(x);
})();
0
Dom 30 août 2020 à 00:43