¿Por qué las promesas ES6 nativas son más lentas y requieren más memoria que el bluebird?

183

En esta referencia , la suite demora 4 veces más en completar con las promesas de ES6 en comparación con las promesas de Bluebird , y usa 3.6 veces más memoria.

¿Cómo puede una biblioteca de JavaScript ser mucho más rápida y liviana que la implementación nativa de v8 escrita en C? Las promesas de Bluebird tienen exactamente la misma API que las promesas nativas de ES6 (más un montón de métodos de utilidad adicionales).

¿La implementación nativa está mal escrita o hay algún otro aspecto que me falta?

    
pregunta callum 10.04.2015 - 22:12

1 respuesta

256

El autor de Bluebird aquí.

La implementación de promesas V8 está escrita en JavaScript no en C. Todo JavaScript (incluido el propio V8) se compila a código nativo. Además, el JavaScript escrito por el usuario se optimiza, si es posible (y vale la pena), antes de compilarlo en código nativo. La implementación de las promesas es algo que no se beneficiaría mucho o no se escribiría en C, de hecho, solo lo haría más lento porque todo lo que está haciendo es manipular los objetos de JavaScript y la comunicación.

La implementación de V8 simplemente no está tan optimizada como bluebird, para las instancias asigna matrices para los manejadores de promesas . Esto requiere una gran cantidad de memoria cuando cada promesa también tiene que asignar un par de matrices (el punto de referencia crea promesas globales de 80k, lo que equivale a 160k de matrices no utilizadas). En realidad, el 99,99% de los casos de uso nunca ramifican una promesa más de una vez, por lo que la optimización de este caso común genera enormes mejoras en el uso de la memoria.

Incluso si V8 implementara las mismas optimizaciones que bluebird, todavía estaría obstaculizado por la especificación. El punto de referencia debe usar new Promise (un anti-patrón en bluebird) ya que no hay otra forma de crear una promesa de raíz en ES6. new Promise es una forma extremadamente lenta de crear una promesa, primero la función ejecutora asigna un cierre, en segundo lugar se pasan 2 cierres separados como argumentos. Son 3 cierres asignados por promesa, pero un cierre ya es un objeto más costoso que una promesa optimizada.

Bluebird puede usar promisify , que permite muchas optimizaciones y es una forma mucho más conveniente de consumir las API de devolución de llamada y permite la conversión de módulos completos en módulos basados en promesa en una línea ( promisifyAll(require('redis')); ).

    
respondido por el Esailija 14.04.2015 - 09:22

Lea otras preguntas en las etiquetas