web-dev-qa-db-fra.com

devrions-nous choisir async attendent plus que Promise en Javascript

Je sais que le async await est la nouvelle Promise de la ville et qu’il s’agit d’une nouvelle façon d’écrire du code asynchrone et je sais aussi que

Nous n'avons pas eu besoin d'écrire .then, de créer une fonction anonyme pour gérer la réponse

Async/await permet enfin de gérer les erreurs synchrones et asynchrones avec la même construction, bon vieux try/catch

La pile d'erreur renvoyée d'une chaîne promise ne donne aucune idée de l'endroit où l'erreur s'est produite. Cependant, la pile d’erreur async/wait pointe sur la fonction qui contient l’erreur

ET SO ON ...

mais ici, j’ai fait un repère simple https://repl.it/repls/FormalAbandonedChimpanzee

Dans l’indice de référence, j’ai exécuté 2 boucles 1 million de fois . Dans la première boucle, j’appelle une fonction renvoyant 1dans une autre fonction, j’appelle une fonction qui renvoie 1 par exception.

le temps pris par la première boucle qui appelle une fonction qui renvoie 1 équivaut à près de la moitié de la fonction qui renvoie 1 comme erreur.

Ce qui montre que le temps pris par throw est presque le double du temps pris par return

node v7.4 linux/AMD64

return takes 1.233seconds
1000000
throw takes 2.128seconds
1000000

Code de référence ci-dessous

function f1() {
  return 1;
}

function f2() {
  throw 1;
}

function parseHrtimeToSeconds(hrtime) {
    var seconds = (hrtime[0] + (hrtime[1] / 1e9)).toFixed(3);
    return seconds;
}

var sum = 0;
var start = 0;
var i = 0;

start = process.hrtime();
for (i = 0; i < 1e6; i++) {
  try {
    sum += f1();
  } catch (e) {
    sum += e;
  }
}
var seconds = parseHrtimeToSeconds(process.hrtime(start));
console.log('return takes ' + seconds + 'seconds');
console.log(sum);




sum = 0;
start = process.hrtime();
for (i = 0; i < 1e6; i++) {
  try {
    sum += f2();
  } catch (e) {
    sum += e;
  }
}

seconds = parseHrtimeToSeconds(process.hrtime(start));
console.log('throw takes ' + seconds + 'seconds');
console.log(sum);
8
Vikas Bansal

Votre repère n'a rien à voir avec la performance entre async/await et les promesses brutes. Tout ce que je peux voir, c'est que lancer une erreur prend plus de temps à calculer. Ceci est prévu.

Retour à la question principale, faut-il utiliser async/await plutôt que .then avec des promesses brutes?

Gardez à l'esprit que async/await n'est que du sucre syntaxique par rapport aux promesses brutes, de sorte qu'il ne devrait pas y avoir beaucoup d'impact sur les performances globales. Cependant, cela rend votre code plus linéaire, ce qui supprime une surcharge cognitive du développeur.

La conclusion est d'utiliser ce que vous préférez. Les promesses peuvent être multifonctionnelles, mais les nouvelles syntaxes ne le peuvent pas. Vous voudrez peut-être garder cela à l'esprit lorsque vous déciderez du style à utiliser.


Certains malentendus:

La pile d'erreur renvoyée d'une chaîne de promesses ne donne aucune idée de l'endroit où l'erreur s'est produite

Ce n'est pas vrai. Une vérification rapide avec:

function error() {
    return new Promise(function(res, rej) {
        res(undefined()); // uh oh
    });
}

error().then(console.log, e => console.log("Uh oh!", e.stack));

affiche la pile d'erreur complète, y compris l'emplacement.

12
Derek 朕會功夫

Comme la plupart des choses vont, la réponse est "ça dépend".

Avant de parler de performance, l’aspect le plus important est la maintenabilité du code et la limitation de async/await par rapport à raw Promise.

async/await est un excellent moyen d'exécuter du code asynchrone séquentiellement, alors que Promise vous permet d'exécuter du code asynchrone simultanément.

async function foo() {
  const a = await backend.doSomething()
  const b = await backend.doAnotherThing()
  return a + b
}

Dans le code ci-dessus, backend.doAnotherThing() ne sera exécuté que lorsque backend.doSomething() sera retourné. D'autre part:

function foo() {
  Promise.all([backend.doSomething(), backend.doAnotherThing()])
    .then(([a, b]) => {
       return a + b
    })
}

exécutera les deux appels et attendra que les deux se terminent.

Comme vous l'avez mentionné à propos des avantages de async/await, personnellement, je l'utilise beaucoup. Sauf les cas ci-dessus.

Si vous avez besoin de performances et que vous avez besoin de vous, la différence de performances entre async/await et Promise est plus importante que l’avantage en lisibilité de async/await sur Promise, va de soi.

Tant que c'est un choix conscient, ça devrait aller.

MISE À JOUR: comme mentionné par Derek 會 功夫

Vous pouvez obtenir une exécution parallèle avec async/await en:

async function foo() {
  const p1 = backend.doSomething()
  const p2 = backend.doAnotherThing()
  return await p1 + await p2
}
7
unional

Construire sur la réponse de unional :

Vous pouvez obtenir le même comportement que Promise.all avec async/await

function foo() {
  Promise.all([backend.doSomething(), backend.doAnotherThing()])
    .then(([a, b]) => {
       return a + b
    })
}

async function foo() {
  const a = backend.doSomething()
  const b = backend.doAnotherThing()
  return await a + await b
}

Les tâches principales se déroulent simultanément et nous attendons que les deux tâches soient terminées avant de revenir. Voir aussi l'exemple MDN que j'ai écrit

Sur cette base, je ne suis pas sûr que l’utilisation directe de Promises sur async/await présente un avantage en termes de performances. 

1
spygi