2015-01-06 23 views
5

Tôi có một ứng dụng mà tôi phải đẩy một giá trị rất nhiều để mảng, vì vậy tôi kiểm tra thời gian thực hiện:setTimeout trong javascript chức năng làm cho chạy nhanh hơn

var st = new Date().getTime(); 
var a = []; 
for (var i = 0; i < 20971520; i++) { 
    a.push(i); 
} 
var ed = new Date().getTime(); 
console.info((ed - st)/1000); 
console.info(a.length); 

tôi chạy các mã trong Firefox Console và Chrome giao diện điều khiển trực tiếp và chi phí là 37 seconds. Và trong quá trình thực hiện, ngay cả chuột cũng có thể được di chuyển trong Chrome nhưng không có hiệu ứng tương tác.

Sau đó tôi thay đổi mã:

function push() { 
    var st = new Date().getTime(); 
    var a = []; 
    for (var i = 0; i < 20971520; i++) { 
    a.push(i); 
    } 
    var ed = new Date().getTime(); 
    console.info((ed - st)/1000); 
    console.info(a.length); 
} 

var tr = setTimeout(push, 50); 

Đơn giản hóa đưa các mã trong một hàm, và gọi nó bằng cách sử dụng setTimeout, nó có giá 0.844 second. Và trong quá trình thực hiện, tôi có thể hoạt động bình thường trong Chrome.

Screenshot of console

gì đang xảy ra ở đây?

Tôi biết rằng setTimeout sẽ đặt điều khiển cho trình duyệt để thực hiện công việc giao diện người dùng, điều này sẽ làm cho trang phản hồi. Ví dụ: khi tôi thực hiện một số phép tính trong khi di chuột qua trang, tôi sẽ đặt phép tính được thực hiện chậm để ngăn chặn việc chặn giao diện người dùng.

Nhưng tại sao lại giảm tổng thời gian thực thi của cùng một mã?

+1

Có thể nó chỉ là bộ nhớ đệm. Bạn đã thử trao đổi thứ tự thực hiện chưa, tức là trước tiên chạy biến thể setTimeout và sau đó là biến thể khác? –

+0

Điều gì sẽ xảy ra nếu bạn chỉ gọi 'push() '? – Freez

+0

Phải mất cùng một thời gian có hoặc không có thời gian chờ cho tôi. – DoctorMick

Trả lời

5

Và trong quá trình thực thi, tôi có thể hoạt động trong Chrome bình thường.

Không đúng sự thật. Cửa sổ chrome chính sẽ chỉ đóng băng như trường hợp khác (chỉ trong một thời gian ngắn hơn). Các công cụ gỡ lỗi là một chủ đề riêng biệt và sẽ không làm chậm mặc dù.

Nhưng tại sao lại giảm tổng thời gian thực thi của cùng một mã?

Nó sẽ hoạt động nếu bạn chạy trong các công cụ dành cho nhà phát triển. Nếu bạn thực thi mã trong thực tế nơi VM có thể làm cho tối ưu hóa thuộc tính thì thời gian có thể so sánh (gần 1 giây). ví dụ.

var st = new Date().getTime(); 
    var a = []; 
    for (var i = 0; i < 20971520; i++) { 
     a.push(i); 
    } 
    var ed = new Date().getTime(); 
    console.info('normal', (ed - st)/1000); 
    console.info(a.length); 

    function push() { 
     var st = new Date().getTime(); 
     var a = []; 
     for (var i = 0; i < 20971520; i++) { 
      a.push(i); 
     } 
     var ed = new Date().getTime(); 
     console.info('timeout', (ed - st)/1000); 
     console.info(a.length); 
    } 

    var tr = setTimeout(push, 0); 

http://jsfiddle.net/gu9Lg52j/ bạn sẽ thấy những normal thực hiện cũng nhanh như setTimeout.

Ngoài ra nếu bạn quấn mã trong một hàm và thực hiện trong một giao diện điều khiển thời điểm đó sẽ được so sánh ngay cả khi không một setTimeout như VM có thể làm cho việc tối ưu giữa định nghĩa hàm và thực hiện:

function push() { 
     var st = new Date().getTime(); 
     var a = []; 
     for (var i = 0; i < 20971520; i++) { 
      a.push(i); 
     } 
     var ed = new Date().getTime(); 
     console.info('timeout', (ed - st)/1000); 
     console.info(a.length); 
    } 
    push(); 
+0

Fiddle của bạn sử dụng 'onload' thay đổi cách mã được thực hiện. –

+0

@SalmanA bạn đã đúng. Tôi đã thay đổi fiddle để thực thi thô và kết quả vẫn có thể so sánh được. – basarat

1

Tất cả JavaScript thực hiện tối ưu hóa khác nhau. Ví dụ, V8 sử dụng 2 trình biên dịch, một trình biên dịch đơn giản được sử dụng theo mặc định và một trình tối ưu hóa. Mã không được biên dịch bởi trình biên dịch tối ưu hóa là chậm, rất chậm.

Điều kiện để trình biên dịch tối ưu hóa chạy là mã phải nằm trong hàm (không quá dài) (there are other conditions). Mã đầu tiên bạn đã thử trong bảng điều khiển không có trong hàm. Đặt mã đầu tiên của bạn vào một hàm và bạn sẽ thấy nó thực hiện giống như mã thứ hai, setTimeout không thay đổi gì cả.

Nó làm cho không có ý nghĩa để kiểm tra xem có các buổi biểu diễn trong bảng điều khiển khi các yếu tố hiệu suất chính là việc soạn thảo tối ưu hóa. Nếu bạn đang nhắm mục tiêu đến nút, hãy sử dụng khung đo điểm chuẩn. Nếu bạn đang nhắm mục tiêu trình duyệt, hãy sử dụng trang web như jsperf.

Bây giờ, khi bạn phải thực hiện tính toán thực sự dài trong trình duyệt (dường như không phải như vậy), bạn nên xem xét using web workers thực hiện công việc trong chuỗi nền không ảnh hưởng đến giao diện người dùng.

+0

Làm thế nào về nếu tôi phải chạy dài tính toán trong Nodewebkit, trên thực tế, tôi chỉ tự hỏi nếu tạo một mảng với hàng triệu yếu tố sẽ chặn giao diện người dùng? Đó là lý do tại sao tôi kiểm tra chức năng. – hguser

2

Cả hai biến thể của mã nên chạy với tốc độ gần như giống hệt nhau (ví dụ thứ hai có thể là nhanh hơn nhưng nhanh hơn chứ không phải 10 lần).

Bên trong các công cụ nhà phát triển Chrome, có một câu chuyện khác nhau. Các biểu thức được đánh giá bên trong khối with. Điều này có nghĩa là các biến như ai được tìm kiếm đầu tiên bên trong một đối tượng khác (__commandLineAPI). Điều này cho biết thêm một chi phí bổ sung mà kết quả trong thời gian thực hiện lâu hơn 10 lần.

+0

Đó không thực sự là lý do. Chức năng (IIFE) của bạn là lý do. –

+0

Vấn đề là trong ví dụ này, bạn đang đẩy bên trong một biến cục bộ 'a' thay vì' window.a'. –

+0

Có, nhưng điều đó không ảnh hưởng đến hiệu suất nhiều như việc đặt mã trong một hàm (thử với 'window.a') –

0

setTimeout, như những người khác nhận thấy, không tăng tốc độ tạo mảng và làm khóa trình duyệt. Nếu bạn quan ngại về việc khóa trình duyệt trong khi tạo mảng, nhân viên web (xem MDN) có thể đến để giải cứu. Đây là bản trình diễn jsFiddle sử dụng nhân viên web cho mã của bạn. Mã công nhân nằm trong html:

onmessage = function (e) { 
    var a = [], now = new Date; 
    for (var i=0; i<20971520; i++) { 
    a.push(i); 
    } 
    postMessage({timings: 'duration: '+(new Date()-now) + 
         'Ms, result: [' + a[0] + '...'+a[a.length-1] + ']'}); 
} 
Các vấn đề liên quan