Jan de Mooij từ nhóm Mozilla đã đăng một số chi tiết trong số Bugzilla thread. Dưới đây là cách giải thích đơn giản của tôi về các câu trả lời kỹ thuật cao của mình:
Trong trường hợp i < 8
, Firefox đủ thông minh để tránh câu trả lời result = t instanceof Test;
(theo thử nghiệm của tôi, dường như nó không hoàn toàn bỏ qua). Trong trường hợp i < 9
, dường như không thực hiện tối ưu hóa đó.
Tại sao? Lý do không rõ ràng, nhưng nó có lẽ liên quan đến thực tế là 9 lần lặp lại là ngưỡng trên mà hàm được coi là "nóng" đủ để chạy nó thông qua trình biên dịch JIT. Trường hợp i < 8
vẫn còn trong thông dịch viên. (Tôi không thấy lý do tại sao JIT-ing sẽ loại trừ cẩu, nhưng dường như nó có trong phiên bản hiện tại của động cơ.)
Điều thú vị là ngưỡng 8 lần không có vẻ phổ quát. Ví dụ, nếu chúng ta thay thế nguyên mẫu của chúng ta (Test
) với một built-in nguyên mẫu (ví dụ CustomEvent
), cẩu dường như không xảy ra không phụ thuộc vào số lần lặp (relevant JSPerf):
for (var i = 0; i < 8; i++) { //or i < 9
t instanceof CustomEvent;
}
Coming back to mã ban đầu sử dụng nguyên mẫu Test
, tại sao hiệu suất lại xấu như vậy trong trường hợp i < 9
? Điều này liên quan đến cách JSPerf hoạt động. Mã "thiết lập" không chỉ được thực hiện một lần - nó được chạy một lần "cho mỗi thử nghiệm". Mỗi khi bạn nhấp vào Chạy, JSPerf chạy hàng trăm "kiểm tra", mỗi thử nghiệm bao gồm hàng nghìn lần lặp. Vì vậy, mã thiết lập được chạy hàng trăm lần.Điều này có nghĩa rằng có hàng trăm đối tượng nguyên mẫu khác nhau được đặt tên Test
trong chương trình, tất cả tạo ra với các dòng:
Test = function(){
}
Các Ion JIT tối ưu hóa trình biên dịch có thể dễ dàng tối ưu hóa các trường hợp mà chúng ta đang sử dụng instanceof
trên đối tượng nguyên mẫu cùng nhiều lần (như chúng ta làm với CustomEvent
trong this test case), nhưng khi nó nhận thấy rằng có nhiều hơn một đối tượng có cùng tên, dường như nó ném tay trong không khí.
Jan đã chỉ ra rằng điều này không có khả năng ảnh hưởng đến quá nhiều tập lệnh thực tế vì thông thường một mã định danh duy nhất được liên kết với một đối tượng mẫu đơn (ví dụ: bạn có một lớp Foobar
, được xác định chỉ một lần và không bao giờ trở lại -defined). Nhưng JSPerf định nghĩa lại nguyên mẫu hàng trăm lần. Dường như với tôi rằng thực tế này thực hiện nghi ngờ nghiêm trọng về tất cả các kết quả JSPerf được công bố bao gồm các định nghĩa nguyên mẫu, ngoại trừ những định nghĩa rõ ràng tránh định nghĩa lại bằng cách sử dụng các hình cầu (như trong test case) - đó có lẽ là kết luận quan trọng nhất.
Ví dụ: các kiểm tra JSPerf được liên kết từ câu hỏi này: Is using instanceof operator in javascript a performance issue? có thể vô giá trị vì chúng đều xác định nguyên mẫu trong mã thiết lập.
Điều thú vị là nó không xảy ra khi bạn thực hiện nội tuyến 8/9 lần: http://jsperf.com/instanceof-8-times-vs-9-times/3. Cũng không xảy ra trên Firefox 40.3. – ralh
Làm một vòng lặp đệ quy vào một hàm có vẻ nhanh hơn. Quirky. – Chris
Cảm ơn bạn đã mở một lỗi cho vấn đề này (https://bugzilla.mozilla.org/show_bug.cgi?id=1210342). Đoán mù của tôi sẽ là đây chỉ là chi phí của việc biên dịch trình biên dịch cơ bản xuất hiện khi chúng ta nhập vòng lặp thêm một lần nữa. Nếu bạn sử dụng số lần lặp lại lớn hơn, chi phí của mỗi lần lặp lại sẽ được khấu hao. – nbp