Dlaczego natywne ES6 obiecuje wolniejsze i bardziej wymagające pamięci niż Bluebird?

195

W tym teście pakiet zajmuje 4 razy więcej czasu, niż spełnienie obietnic ES6 w porównaniu z obietnicami Bluebird, i zużywa 3,6 razy więcej pamięci.

W jaki sposób biblioteka JavaScript może być znacznie szybsza i lżejsza niż natywna implementacja v8 napisana w C? Obietnice Bluebird mają dokładnie taki sam interfejs API jak natywne obietnice ES6 (plus kilka dodatkowych metod narzędziowych).

Czy natywna implementacja jest po prostu źle napisana, czy też brakuje mi jakiegoś innego aspektu?

kalus
źródło
Pamiętaj, że nowoczesne implementacje JavaScript są mocno zoptymalizowane, a nawet mogą działać natywnie przy użyciu JIT .
1
Według This Benchmark BlueBirdJS jest rzeczywiście wolniejszy niż Native Promises. Ale PromiseMeSpeedJS faktycznie wyprzedza oba z nich. Jedną z wielu rzeczy, które potwierdza PromiseMeSpeedJS, jest to, że głównym winowajcą wydajności w obietnicach jest nadużywanie newoperatora, ponieważ PromiseMeSpeedJS nie korzysta new.
Jack Giffin
1
@JackGiffin Chrome 67: PromiseMeSpeedJS jest o 46% wolniejszy, a Bluebird o 61% wolniejszy.
FINDarkside

Odpowiedzi:

272

Autor Bluebird tutaj.

V8 obiecuje, że implementacja jest napisana w JavaScript, a nie C. Cały JavaScript (w tym własny V8) jest kompilowany do kodu natywnego. Dodatkowo JavaScript napisany przez użytkownika jest zoptymalizowany, jeśli to możliwe (i warto), przed skompilowaniem do kodu natywnego. Implementacja obietnic jest czymś, co nie przyniosłoby wiele korzyści lub wcale nie byłoby napisane w C, w rzeczywistości spowolniłoby to, ponieważ wszystko, co robisz, to manipulowanie obiektami JavaScript i komunikacją.

Implementacja V8 po prostu nie jest tak zoptymalizowana jak bluebird, na przykład alokuje tablice dla programów obsługi obietnic . Zajmuje to dużo pamięci, gdy każda obietnica musi również przydzielić kilka tablic (test porównawczy tworzy ogólnie 80 tys. Obietnic, więc przydzielono 160 tys. Nieużywanych tablic). W rzeczywistości 99,99% przypadków użycia nigdy nie rozgałęzia obietnicy więcej niż jeden raz, więc optymalizacja dla tego typowego przypadku zyskuje ogromne ulepszenia wykorzystania pamięci.

Nawet jeśli V8 zaimplementowałoby te same optymalizacje, co Bluebird, nadal byłoby to utrudnione przez specyfikację. Benchmark musi zostać wykorzystany new Promise(anty-wzór w bluebird), ponieważ nie ma innego sposobu na stworzenie obietnicy root w ES6. new Promiseto niezwykle powolny sposób tworzenia obietnicy, najpierw funkcja executora przydziela zamknięcie, po drugie przekazuje 2 oddzielne zamknięcia jako argumenty. To 3 zamknięcia przydzielone na obietnicę, ale zamknięcie jest już droższym przedmiotem niż zoptymalizowana obietnica.

Można użyć Bluebird, promisifyktóry umożliwia wiele optymalizacji i jest znacznie wygodniejszym sposobem korzystania z interfejsów API wywołania zwrotnego oraz umożliwia konwersję całych modułów na moduły oparte na obietnicach w jednym wierszu ( promisifyAll(require('redis'));).

Esailija
źródło
10
„wciąż przeszkadza specyfikacja” - Nie jestem pewien, co to oznacza. Czy mówisz, że ES6 podąża za specyfikacją, która jest z natury powolna, a jeśli tak, to czy oznacza to, że bluebird nie stosuje się do tej samej specyfikacji (a jeśli tak, to czy podąża za inną i która?) I czy jest jakiś powód, dla którego ES6 nie może mieć lepszego sposobu na stworzenie głównej obietnicy poza tym new Promiselub poprawy instancji, aby uczynić ją tańszą (np. Nie tworząc 3 zamknięć na instancję)?
Anthony
12
To wcale nie brzmi dobrze (dla JS). Naprawdę nie chcę używać biblioteki Promise, gdy istnieje wewnętrzna implementacja. Jest to bardziej niż niefortunna sytuacja dla wszystkich, jeśli to wszystko prawda. Ale ja już mam problemy z widzeniem Promise-szumu tak, pisałem 100.000 LoC JS aplikacje i nadal nie widzę żadnej realnej potrzeby tego, że jest to bardzo niewielka poprawa, jeśli w ogóle do mnie , głównie w obsługę błędów, nie poprawa obsługi oddzwaniania (nigdy nie byłem w „piekle oddzwaniania” z moim stylem kodowania).
Mörre
19
Czy w ES6 nie można użyć Promise.resolve()„obietnicy root”?
zetlen,
10
@ MörreNoseshine (ciąg dalszy) Wiele lat później pojawili się autorzy ES6 i powiedzieli „hej, określmy, że silniki JS muszą zapewniać gotowe narzędzie zgodne z obietnicami / A +, aby ludzie zawsze mieli podstawowe narzędzie do obiecania „. Jest to niezła wygoda (nie trzeba importować biblioteki tylko po to, aby zrobić coś szybko Promise.resolve()lub cokolwiek), ale jest to bardzo podstawowa implementacja, a jej istnienie nie powinno zniechęcać do korzystania z poważniejszych narzędzi związanych z obietnicami, takich jak bluebird!
callum
11
@ MörreNoseshine 100k LOC Aplikacja JavaScript, która prawdopodobnie nigdy nie miała żadnej funkcji asynchronicznej. Powodzenia w pisaniu 100k LoC JS z biblioteką mysql / redis bez bluebirda.
NiCk Newman