Mengapa ES6 asli menjanjikan lebih lambat dan lebih banyak memori-intensif daripada burung blu

195

Dalam tolok ukur ini , paket membutuhkan waktu 4 kali lebih lama untuk dilengkapi dengan janji ES6 dibandingkan dengan janji Bluebird, dan menggunakan memori 3,6 kali lebih banyak.

Bagaimana pustaka JavaScript bisa lebih cepat dan lebih ringan daripada implementasi asli v8 yang ditulis dalam C? Janji Bluebird memiliki API yang persis sama dengan janji ES6 asli (ditambah banyak metode utilitas tambahan).

Apakah implementasi asli hanya ditulis dengan buruk, atau ada aspek lain yang saya lewatkan?

callum
sumber
Perlu diingat bahwa implementasi JavaScript modern sangat dioptimalkan, dan bahkan dapat berjalan secara native menggunakan JIT .
1
Menurut Ini Benchmark , BlueBirdJS sebenarnya lebih lambat dari Native Promises. Tapi, PromiseMeSpeedJS sebenarnya mengalahkan mereka berdua. Salah satu dari banyak hal yang dibuktikan PromiseMeSpeedJS melalui ini adalah bahwa penyebab utama kinerja untuk janji-janji adalah penyalahgunaan berlebihan newoperator karena PromiseMeSpeedJS tidak menggunakan new.
Jack Giffin
1
@JackGiffin Chrome 67: PromiseMeSpeedJS 46% lebih lambat dan Bluebird lebih lambat 61%.
FINDarkside

Jawaban:

272

Penulis bluebird di sini.

Implementasi V8 berjanji ditulis dalam JavaScript bukan C. Semua JavaScript (termasuk milik V8) dikompilasi ke kode asli. Selain itu, JavaScript yang ditulis pengguna dioptimalkan, jika mungkin (dan layak), sebelum dikompilasi dengan kode asli. Menjanjikan implementasi adalah sesuatu yang tidak akan mendapat banyak manfaat atau sama sekali dari ditulis dalam C, pada kenyataannya itu hanya akan membuatnya lebih lambat karena semua yang Anda lakukan adalah memanipulasi objek JavaScript dan komunikasi.

Implementasi V8 tidak seoptimal bluebird, contohnya mengalokasikan array untuk penangan janji . Ini membutuhkan banyak memori ketika setiap janji juga harus mengalokasikan beberapa array (Benchmark menciptakan keseluruhan 80 ribu janji sehingga 160r dialokasikan array yang tidak digunakan). Pada kenyataannya, 99,99% kasus penggunaan tidak pernah menumbuhkan janji lebih dari sekali sehingga mengoptimalkan untuk kasus umum ini mendapatkan peningkatan penggunaan memori yang sangat besar.

Bahkan jika V8 mengimplementasikan optimasi yang sama seperti bluebird, itu masih akan terhalang oleh spesifikasi. Patokan harus menggunakan new Promise(anti-pola di bluebird) karena tidak ada cara lain untuk membuat janji root di ES6. new Promiseadalah cara yang sangat lambat untuk membuat janji, pertama fungsi pelaksana mengalokasikan penutupan, kedua melewati 2 penutupan terpisah sebagai argumen. Itu adalah 3 penutupan yang dialokasikan per janji tetapi penutupan sudah merupakan objek yang lebih mahal daripada janji yang dioptimalkan.

Bluebird dapat menggunakan promisifyyang memungkinkan banyak optimasi dan merupakan cara yang jauh lebih nyaman untuk mengonsumsi API panggilan balik dan memungkinkan konversi seluruh modul menjadi modul berbasis janji dalam satu baris ( promisifyAll(require('redis'));).

Esailija
sumber
10
"masih terhalang oleh spesifikasi" - Tidak yakin apa artinya itu. Apakah Anda mengatakan bahwa ES6 mengikuti spec yang secara inheren lambat, dan jika itu masalahnya, apakah itu berarti burung bluebird tidak mengikuti spec yang sama (dan jika itu masalahnya, apakah itu mengikuti yang berbeda, dan yang mana)? Dan adakah alasan mengapa ES6 tidak memiliki cara yang lebih baik untuk membuat Janji root selain new Promiseatau meningkatkan instantiasi untuk membuatnya lebih murah (seperti tidak membuat 3 penutupan per instance)?
Anthony
12
Kedengarannya tidak bagus sama sekali (untuk JS). Saya benar-benar tidak ingin menggunakan perpustakaan Promise ketika ada implementasi internal. Ini adalah situasi yang lebih disayangkan bagi semua orang jika ini semua benar. Tapi saya sudah mengalami kesulitan melihat Promise-hype, saya telah menulis 100.000 aplikasi JS LoC dan saya masih tidak melihat adanya kebutuhan nyata untuk ini, ini adalah peningkatan yang sangat kecil jika sama sekali bagi saya , kebanyakan dalam penanganan kesalahan, tidak ada peningkatan dalam penanganan panggilan balik (Saya tidak pernah berada di "panggilan balik neraka" dengan gaya pengkodean saya).
Mörre
19
Di ES6, tidak bisakah Anda menggunakan Promise.resolve()untuk membuat "janji root"?
zetlen
10
@ MörreNoseshine (lanjutan) Bertahun-tahun kemudian, para penulis ES6 datang dan berkata "hei, mari kita tentukan bahwa mesin JS harus menyediakan utilitas generik Janji / A + sesuai di luar kotak, sehingga orang selalu memiliki alat janji dasar untuk diberikan ". Ini adalah kenyamanan yang bagus (tidak harus mengimpor perpustakaan hanya untuk melakukan yang cepat Promise.resolve()atau apa pun), tetapi ini adalah implementasi yang sangat mendasar, dan keberadaannya seharusnya tidak membuat Anda menunda menggunakan alat yang berhubungan dengan janji yang lebih serius seperti bluebird!
callum
11
@MörreNoseshine 100k LOC aplikasi Javascript yang mungkin tidak pernah memiliki fungsi async. Selamat mencoba menulis game LoC JS 100k dengan perpustakaan mysql / redis tanpa bluebird.
NiCk Newman