2011-08-17 96 views
18

Tôi biết bạn nên lướt nhẹ khi thực hiện các cuộc gọi đệ quy đến các hàm trong JavaScript vì cuộc gọi thứ hai của bạn có thể chậm hơn tới 10 lần.Gọi hàm đệ quy trong JavaScript

Eloquent JavaScript trạng thái:

Có một vấn đề quan trọng: Trong hầu hết các trường JavaScript, phiên bản thứ hai này là khoảng 10 lần chậm hơn lần thứ nhất. Trong JavaScript, chạy một vòng lặp đơn giản rẻ hơn rất nhiều so với việc gọi một hàm nhiều lần.

John Resig thậm chí còn cho biết đây là sự cố trong this bài đăng.

Câu hỏi của tôi là: Tại sao việc sử dụng đệ quy lại không hiệu quả? Nó chỉ là cách một động cơ cụ thể được xây dựng? Liệu chúng ta có bao giờ nhìn thấy một thời gian trong JavaScript mà đây không phải là trường hợp?

+1

Tôi đoán đó là phạm vi: P Câu hỏi hay, tôi tò mò là câu trả lời của họ! – Pelshoff

+4

Chi phí cuộc gọi chức năng đơn giản là lớn hơn điều khiển vòng lặp; điều đó đúng với bất kỳ ngôn ngữ lập trình nào. Có rất nhiều sổ sách kế toán để thực hiện khi gọi một hàm: phân bổ và khởi tạo một phạm vi mới, lưu địa chỉ trả về, sắp xếp các tham số, v.v. Lưu ý rằng các trình thông dịch JavaScript đã nhanh hơn với tốc độ rất nhanh, vì vậy các mẹo thực hiện trong 3 bài viết blog cũ (hoặc sách) nên được đặt câu hỏi. – Pointy

+1

"vì cuộc gọi thứ hai của bạn có thể chậm hơn tới 10 lần" Đó không phải là nội dung của văn bản. Nó nói rằng phiên bản thứ hai của mã chậm hơn 10 lần. –

Trả lời

11

Cuộc gọi chức năng chỉ đắt hơn một vòng lặp đơn giản do tất cả chi phí thay đổi ngăn xếp và thiết lập ngữ cảnh mới, v.v. Để đệ quy trở nên rất hiệu quả, một ngôn ngữ phải hỗ trợ một số dạng cắt bỏ cuộc gọi đuôi, về cơ bản có nghĩa là chuyển đổi một số loại hàm đệ quy nhất định thành các vòng lặp. Các ngôn ngữ chức năng như OCaml, Haskell và Scheme thực hiện điều này, nhưng không thực hiện JavaScript mà tôi nhận thức được (nó sẽ chỉ hữu ích một cách hữu ích trừ khi tất cả chúng đều có, vì vậy có lẽ chúng ta có vấn đề về triết lý ăn uống).

+5

ES6 nên có tối ưu hóa cuộc gọi đuôi. [Cuộc gọi đuôi thích hợp] (http://wiki.ecmascript.org/doku.php?id=harmony:proper_tail_calls) – Raynos

3

Đây chỉ là cách mà các công cụ JS cụ thể mà trình duyệt sử dụng được xây dựng, có. Nếu không có cuộc gọi loại bỏ đuôi, bạn phải tạo một khung ngăn xếp mới mỗi khi bạn recurse, trong khi với một vòng lặp nó chỉ cần thiết lập các chương trình truy cập trở lại để bắt đầu của nó. Đề án, ví dụ, có điều này như là một phần của đặc tả ngôn ngữ, vì vậy bạn có thể sử dụng đệ quy theo cách này mà không đáng lo ngại về hiệu suất.

https://bugzilla.mozilla.org/show_bug.cgi?id=445363 cho biết tiến trình đang được thực hiện trong Firefox (và Brendan Eich nói ở đây về nó có thể là một phần của thông số ECMAScript), nhưng tôi không nghĩ bất kỳ trình duyệt hiện tại nào đã được triển khai thực hiện.

Các vấn đề liên quan