2009-03-23 34 views
50

Tôi có JavaScript thực hiện rất nhiều tính toán cũng như các giá trị đọc/ghi từ/đến DOM. Trang này rất lớn nên điều này thường kết thúc khóa trình duyệt trong tối đa một phút (đôi khi lâu hơn với IE) với mức sử dụng CPU 100%.Ngăn JavaScript chạy dài từ khóa trình duyệt

Có tài nguyên nào để tối ưu hóa JavaScript để ngăn điều này xảy ra hay không (tất cả những gì tôi có thể tìm thấy là cách tắt cảnh báo tập lệnh chạy dài của Firefox)?

Trả lời

44

nếu bạn có thể biến thuật toán tính toán thành thứ gì đó có thể được gọi lặp lại, bạn có thể phát hành kiểm soát trình duyệt thường xuyên bằng cách sử dụng setTimeout với giá trị thời gian chờ ngắn.

Ví dụ, một cái gì đó như thế này ...

function doCalculation() 
{ 
    //do your thing for a short time 

    //figure out how complete you are 
    var percent_complete=.... 

    return percent_complete; 
} 

function pump() 
{ 
    var percent_complete=doCalculation(); 

    //maybe update a progress meter here! 

    //carry on pumping? 
    if (percent_complete<100) 
    { 
     setTimeout(pump, 50); 
    } 
} 

//start the calculation 
pump(); 
+2

Bạn có biết điều này sẽ vẫn hoạt động nếu bạn sử dụng 'setTimeout (pump, 0)'? Hoặc điều này có thể giữ trước khi làm trống mã trình duyệt đáp ứng với đầu vào chuột, cập nhật đồng hồ tiến trình hoặc các phần tử DOM khác không? – Andy

+0

@Andy Có 'setTimeout' với 0 cũng sẽ giúp ích. Xem một số câu trả lời cho [câu hỏi này] (https://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful). – ShreevatsaR

1

Bạn có thể thử thực hiện các phép tính dài chạy trong các chủ đề (xem JavaScript and Threads), mặc dù chúng không phải là rất di động.

Bạn cũng có thể thử sử dụng một số trình lược tả Javascript để tìm các nút cổ chai hiệu suất. Firebug hỗ trợ định dạng javascript.

7

Sử dụng hết thời gian chờ.

Bằng cách đặt nội dung của vòng lặp của bạn vào các chức năng riêng biệt và gọi chúng từ setTimeout() với thời gian chờ là 50 hoặc hơn, javascript sẽ kiểm soát luồng và quay lại sau, cho phép Giao diện người dùng để có giao diện.

Có một bài tập tốt here.

2

Tôi đã viết blog về in-browser performance một số thời gian trước đây, nhưng hãy để tôi tóm tắt những người liên quan đến DOM cho bạn ở đây.

  • Cập nhật DOM càng ít càng tốt. Thực hiện các thay đổi của bạn đối với các đối tượng DOM trong bộ nhớ và chỉ thêm chúng một lần vào DOM.
  • Sử dụng innerHTML. Nó nhanh hơn các phương thức DOM trong hầu hết các trình duyệt.
  • Sử dụng ủy quyền sự kiện thay vì xử lý sự kiện thông thường.
  • Biết cuộc gọi nào đắt tiền và tránh chúng. Ví dụ, trong jQuery, $ ("div.className") sẽ đắt hơn $ ("# someId").

Sau đó, có một số liên quan đến hoạt Javascript chính nó:

  • Vòng càng ít càng tốt. Nếu bạn có một hàm thu thập các nút DOM và một hàm khác xử lý chúng, bạn sẽ lặp lại hai lần. Thay vào đó, chuyển một hàm ẩn danh tới hàm thu thập các nút và xử lý các nút khi bạn thu thập chúng.
  • Sử dụng chức năng gốc khi có thể. Ví dụ, forEach iterators.
  • Sử dụng setTimeout để cho phép trình duyệt hít thở một lần trong một thời gian.
  • Đối với các hàm đắt tiền có kết quả đầu ra không cần thiết, hãy lưu trữ kết quả để bạn không phải tính toán lại nó.

Có một số thông tin khác trên blog của tôi (liên kết ở trên).

1

Điều này vẫn còn một chút chảy máu cạnh, nhưng Firefox 3.5 có những thứ gọi là Web Workers, tôi không chắc chắn về hỗ trợ của họ trong các trình duyệt khác mặc dù.

Ông Resig có một bài viết về họ ở đây: http://ejohn.org/blog/web-workers/

Simulated Annealing có lẽ là ví dụ đơn giản nhất của nó, nếu bạn sẽ nhận thấy biểu tượng quay Firefox không đóng băng lên, khi đề người lao động đang làm yêu cầu của họ (do đó không đóng băng trình duyệt).

+0

Tại sao nhân viên web không phải là câu trả lời ở đây? –

+0

Tôi đã trả lời câu hỏi này vào 09 'vì vậy có lẽ nó không được sử dụng rộng rãi như vậy ... – leeand00

+0

Điểm tốt, chắc chắn là nó cũng nên được nâng lên ngay bây giờ. Sử dụng setTimeout âm thanh hacky với tôi không có vấn đề gì bạn làm trừ khi bạn thực sự cần một thời gian chờ cho một cái gì đó. Nếu bạn truy cập codepen.io trên Chrome Windows ngay bây giờ và thực hiện một thuật toán với độ phức tạp O (N!) Chẳng hạn như tìm tất cả các hoán vị của chuỗi "ABCDEFGHIJKLMNOP", trình duyệt của bạn sẽ bị khóa và không phản hồi. Trong một chuỗi công nhân, giao diện người dùng tiếp tục tự chạy. Đây rõ ràng là câu trả lời đúng. –

1

Trải nghiệm của tôi là thao tác DOM, đặc biệt là trong IE, là vấn đề về hiệu suất nhiều hơn JavaScript "lõi" (lặp, v.v.).

Nếu bạn đang xây dựng các nút, IE nhanh hơn nhiều khi làm như vậy bằng cách xây dựng một chuỗi HTML và sau đó đặt innerHTML trên một vùng chứa hơn là sử dụng các phương thức DOM như createElement/appendChild.

0

Bạn có thể thử rút ngắn mã bằng cách

$(xmlDoc).find("Object").each(function(arg1) { 
    (function(arg1_received) { 
       setTimeout(function(arg1_received_reached) { 

        //your stuff with the arg1_received_reached goes here 

       }(arg1_received), 0) 
      })(arg1) 
}(this)); 

hoặc "cho" vòng thử

for (var i = 0 ; i < 10000 ; i = i + 1) { 
    (function(arg1_received) { 
     setTimeout(function(arg1_received_reached) { 

      //your stuff with the arg1_received_reached goes here 

     }(arg1_received), 0) 
    })(arg1_to_send) 
} 

tôi đã cùng một vấn đề và khách hàng của tôi đã được báo cáo này như lỗi "Giết trang". Nhưng bây giờ tôi juz có một giải pháp tốt nhất cho điều đó. :)

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