web-dev-qa-db-fra.com

Pourquoi les promesses natives d'ES6 sont-elles plus lentes et plus gourmandes en mémoire que Bluebird?

Dans ce benchmark , la suite prend 4 fois plus de temps pour terminer avec les promesses ES6 par rapport aux promesses Bluebird, et utilise 3,6 fois plus de mémoire.

Comment une bibliothèque JavaScript peut-elle être beaucoup plus rapide et plus légère que l'implémentation native de v8 écrite en C? Les promesses Bluebird ont exactement la même API que les promesses natives ES6 (plus un tas de méthodes utilitaires supplémentaires).

L'implémentation native est-elle mal écrite ou y a-t-il un autre aspect qui me manque?

198
callum

Auteur Bluebird ici.

V8 promet que l'implémentation est écrite en JavaScript pas C. Tout JavaScript (y compris le V8) est compilé en code natif. De plus, le JavaScript écrit par l'utilisateur est optimisé, si possible (et en vaut la peine), avant d'être compilé en code natif. L'implémentation de promesses est quelque chose qui ne bénéficierait pas beaucoup ou pas du tout d'être écrit en C, en fait cela ne ferait que le ralentir car tout ce que vous faites est de manipuler des objets JavaScript et la communication.

L'implémentation V8 n'est tout simplement pas aussi optimisée que bluebird, elle pour les instances alloue des tableaux aux gestionnaires de promesses . Cela prend beaucoup de mémoire lorsque chaque promesse doit également allouer quelques tableaux (le test de référence crée globalement 80 000 promesses, ce qui représente 160 000 tableaux inutilisés alloués). En réalité, 99,99% des cas d'utilisation ne ramifient jamais une promesse plus d'une fois, l'optimisation de ce cas commun permet donc d'améliorer considérablement l'utilisation de la mémoire.

Même si V8 implémentait les mêmes optimisations que bluebird, cela resterait entravé par la spécification. Le benchmark doit utiliser new Promise (Un anti-modèle dans bluebird) car il n'y a pas d'autre moyen de créer une promesse racine dans ES6. new Promise Est un moyen extrêmement lent de créer une promesse, premièrement la fonction exécuteur alloue une fermeture, deuxièmement on lui passe 2 fermetures séparées comme arguments. C'est 3 fermetures allouées par promesse mais une fermeture est déjà un objet plus cher qu'une promesse optimisée.

Bluebird peut utiliser promisify qui permet de nombreuses optimisations et est un moyen beaucoup plus pratique de consommer les API de rappel et il permet la conversion de modules entiers en modules basés sur des promesses sur une seule ligne (promisifyAll(require('redis'));).

273
Esailija