ネイティブのES6がbluebirdよりも遅く、より多くのメモリを消費するのはなぜですか?


195

ではこのベンチマーク、スイートは、ブルーバード約束に比べES6の約束を完了するまでに4倍の時間がかかり、多くのメモリと3.6倍を使用しています。

JavaScriptライブラリは、Cで記述されたv8のネイティブ実装よりもはるかに高速で軽量になります。Bluebirdのpromiseは、ネイティブのES6のpromiseとまったく同じAPIを備えています(さらに、多数の追加のユーティリティメソッド)。

ネイティブの実装は間違って書かれているだけですか、それとも私が見逃している他の側面がありますか?


最新のJavaScript実装は大幅に最適化されており、JITを使用してネイティブに実行されることもあることに留意してください。

1
このベンチマークによると、BlueBirdJSは実際にはNative Promisesよりも低速です。しかし、PromiseMeSpeedJSは実際には両方を上回っています。これによりPromiseMeSpeedJSが証明する多くのことの1つは、newPromiseMeSpeedJSが使用しないため、Promiseの主要なパフォーマンスの犯人がオペレーターの乱用であるということnewです。
ジャック

1
@JackGiffin Chrome 67:PromiseMeSpeedJSは46%遅くなり、Bluebirdは61%遅くなります。
FINDarkside

回答:


272

Bluebirdの著者はこちら。

V8は実装が CではなくJavaScriptで記述されることを約束します。すべてのJavaScript(V8自体を含む)はネイティブコードにコンパイルされます。さらに、ネイティブコードにコンパイルされる前に、可能であれば(そしてそれだけの価値がある)ユーザー作成のJavaScriptが最適化されます。Promiseの実装は、Cで記述されてもあまりメリットがないか、まったく役に立たないものです。実際、JavaScriptオブジェクトと通信を操作するだけなので、遅くなります。

V8実装は単純にbluebirdほど最適化されておらず、インスタンス用にpromiseのハンドラーに配列を割り当てます。各プロミスがいくつかの配列を割り当てる必要がある場合、これは多くのメモリを消費します(ベンチマークは全体で80k個のプロミスを作成するため、160k個の未使用配列が割り当てられます)。実際には、ユースケースの99.99%が複数回約束を分岐することはないため、この一般的なケース向けに最適化すると、メモリ使用量が大幅に改善されます。

V8がbluebirdと同じ最適化を実装したとしても、仕様によって妨げられます。new PromiseES6でルートプロミスを作成する他の方法がないため、ベンチマークでは(bluebirdのアンチパターン)を使用する必要があります。new Promiseは、約束を作成する非常に遅い方法です。まず、executor関数がクロージャーを割り当て、次に引数として2つの別々のクロージャーが渡されます。約束ごとに3つのクロージャーが割り当てられますが、クロージャーはすでに最適化された約束よりも高価なオブジェクトです。

Bluebirdはpromisify、多くの最適化を可能にし、コールバックAPIを消費するはるかに便利な方法を使用でき、1行でモジュール全体をpromiseベースのモジュールに変換できます(promisifyAll(require('redis'));)。


10
「まだ仕様によって妨げられている」-それが何を意味するかわからない。ES6は本質的に遅い仕様に従っていると言っていますか?その場合、それはブルーバードが同じ仕様に従っていないことを意味しますか?(その場合は別の仕様に従っていますか?そして、ES6がルートPromiseを作成するより良い方法を持たない、new Promiseまたはインスタンス化を改善してそれをより安価にすることができない理由はありますか(インスタンスごとに3つのクロージャーを作成しないなど)?
アンソニー

12
(JSの場合)それはまったく良く聞こえません。内部実装がある場合、Promiseライブラリを使用したくありません。これがすべて真実ならば、これは誰にとっても不幸な状況です。しかし、私はすでに、それはすべての場合に非常にマイナーな改善だ、私が100,000 LoCはJSのアプリを書いていると私はまだこのための任意の実際の必要性を見ない、とにかくトラブル約束-誇大広告を見を持っている私にはありません、ほとんどはエラー処理で、コールバック処理の改善(コーディングスタイルで「コールバック地獄」に行ったことがない)。
Mörre

19
ES6ではPromise.resolve()、「ルートプロミス」の作成に使用できませんか?
-zetlen

10
ES 「。これは便利な機能です(ライブラリをインポートする必要はありませんPromise.resolve())が、これは非常に基本的な実装であり、その存在により、bluebirdなどのより深刻なプロミス関連のツールを使用する必要がなくなります!
カルム

11
@MörreNoseshine100k LOC Javascriptアプリ。おそらく非同期機能はまったくありませんでした。ブルーバードを使用せずにmysql / redisライブラリを使用して100k LoC JSゲームを作成してください。
ニック・ニューマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.