Tại sao ES6 bản địa hứa hẹn chậm hơn và tốn nhiều bộ nhớ hơn bluebird?


195

Trong điểm chuẩn này , bộ phần mềm mất nhiều thời gian hơn 4 lần để hoàn thành với các lời hứa ES6 so với các lời hứa của Bluebird và sử dụng bộ nhớ gấp 3,6 lần.

Làm thế nào một thư viện JavaScript có thể nhanh hơn và nhẹ hơn nhiều so với triển khai gốc của v8 được viết bằng C? Các lời hứa của Bluebird có API chính xác giống như các lời hứa ES6 gốc (cộng với một loạt các phương thức tiện ích bổ sung).

Là bản triển khai gốc chỉ được viết xấu, hoặc có một số khía cạnh khác cho điều này mà tôi đang thiếu?


Hãy nhớ rằng các triển khai JavaScript hiện đại được tối ưu hóa rất nhiều và thậm chí có thể chạy bằng JIT .

1
Theo Điểm chuẩn này , BlueBirdJS thực sự chậm hơn so với Lời hứa bản địa. Nhưng, PromiseMeSpeedJS thực sự vượt xa cả hai. Một trong nhiều điều mà PromiseMeSpeedJS chứng minh thông qua điều này là một thủ phạm hiệu suất chính cho những lời hứa là sự lạm dụng quá mức của newnhà điều hành vì PromiseMeSpeedJS không sử dụng new.
Jack Giffin

1
@JackGiffin Chrome 67: PromiseMeSpeedJS chậm hơn 46% và Bluebird chậm hơn 61%.
FINDarkside

Câu trả lời:


272

Tác giả Bluebird ở đây.

V8 hứa triển khai được viết bằng JavaScript chứ không phải C. Tất cả JavaScript (bao gồm cả V8) được biên dịch thành mã gốc. Ngoài ra, JavaScript do người dùng viết được tối ưu hóa, nếu có thể (và đáng giá), trước khi được biên dịch thành mã gốc. Hứa hẹn thực hiện là một cái gì đó sẽ không có lợi nhiều hoặc hoàn toàn không được viết bằng C, trên thực tế, nó chỉ làm cho nó chậm hơn vì tất cả những gì bạn đang làm là thao túng các đối tượng và giao tiếp JavaScript.

Việc triển khai V8 đơn giản là không được tối ưu hóa như bluebird, ví dụ, nó phân bổ các mảng cho các trình xử lý của lời hứa . Điều này cần rất nhiều bộ nhớ khi mỗi lời hứa cũng phải phân bổ một vài mảng (Điểm chuẩn tạo ra 80k lời hứa tổng thể để đó là 160k mảng không sử dụng được phân bổ). Trong thực tế, 99,99% các trường hợp sử dụng không bao giờ hứa hẹn nhiều hơn một lần vì vậy tối ưu hóa cho trường hợp phổ biến này sẽ cải thiện việc sử dụng bộ nhớ lớn.

Ngay cả khi V8 thực hiện các tối ưu hóa tương tự như bluebird, nó vẫn sẽ bị cản trở bởi thông số kỹ thuật. Điểm chuẩn phải sử dụng new Promise(một mô hình chống trong bluebird) vì không có cách nào khác để tạo lời hứa gốc trong ES6. new Promiselà một cách cực kỳ chậm để tạo ra một lời hứa, đầu tiên hàm thực thi phân bổ một bao đóng, thứ hai nó được thông qua 2 bao đóng riêng biệt làm đối số. Đó là 3 lần đóng được phân bổ cho mỗi lời hứa nhưng việc đóng lại đã là một đối tượng đắt hơn so với lời hứa được tối ưu hóa.

Bluebird có thể sử dụng promisifycho phép nhiều tối ưu hóa và là cách tiêu thụ API gọi lại thuận tiện hơn nhiều và nó cho phép chuyển đổi toàn bộ mô-đun thành các mô-đun dựa trên lời hứa trong một dòng ( promisifyAll(require('redis'));).


10
"vẫn bị cản trở bởi đặc điểm kỹ thuật" - Không chắc điều đó có nghĩa là gì. Bạn có nói rằng ES6 đang theo dõi một thông số vốn đã chậm, và nếu đó là trường hợp, điều đó có nghĩa là bluebird không theo cùng thông số đó (và nếu đó là trường hợp, thì nó có theo một thông số khác không, và đó là cái nào)? Và có lý do nào khiến ES6 không thể có cách tốt hơn để tạo một Promise gốc bên cạnh new Promisehoặc cải thiện việc khởi tạo để làm cho nó ít tốn kém hơn (như không tạo ra 3 lần đóng mỗi lần)?
Anthony

12
Điều đó có vẻ không tốt chút nào (đối với JS). Tôi thực sự không muốn sử dụng thư viện Promise khi có triển khai nội bộ. Đây là một tình huống không may hơn cho tất cả mọi người nếu điều này hoàn toàn đúng. Nhưng dù sao tôi cũng gặp khó khăn khi xem Promise-hype, tôi đã viết 100.000 ứng dụng LoC JS và tôi vẫn không thấy bất kỳ nhu cầu thực sự nào cho việc này, đó là một cải tiến rất nhỏ nếu với tôi , chủ yếu là xử lý lỗi, không cải thiện xử lý gọi lại (Tôi chưa bao giờ ở trong "địa ngục gọi lại" với phong cách mã hóa của mình).
Mörre

19
Trong ES6, bạn không thể sử dụng Promise.resolve()để tạo "lời hứa gốc"?
zetlen

10
@ MörreNoseshine (tiếp theo) Nhiều năm sau đó, các tác giả ES6 đã đến và nói "này, hãy xác định rằng các công cụ JS phải cung cấp một tiện ích tuân thủ chung hứa hẹn / A +, vì vậy mọi người luôn có sẵn một công cụ hứa hẹn cơ bản ". Đây là một thuận tiện tốt (không phải nhập thư viện chỉ để thực hiện nhanh chóng Promise.resolve()hoặc bất cứ điều gì), nhưng đó là một triển khai rất cơ bản và sự tồn tại của nó không nên khiến bạn ngừng sử dụng các công cụ liên quan đến lời hứa nghiêm túc hơn như bluebird!
callum

11
@ MörreNoseshine Ứng dụng Javascript 100k có lẽ chưa bao giờ có bất kỳ chức năng không đồng bộ nào. Chúc may mắn khi viết một trò chơi LoC JS 100k với thư viện mysql / redis không có bluebird.
NiCk Newman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.