2013-05-03 20 views
5

Tôi có chức năng chạy dài. Mà lặp qua một mảng lớn và thực hiện một hàm trong mỗi vòng lặp.Cách chia nhỏ chức năng chạy dài trong javascript, nhưng giữ hiệu suất

longFunction : function(){ 
     var self = this; 
     var data = self.data; 

     for(var i=0; len = data.length; i<len; i++){ 
       self.smallFunction(i); 
     } 
}, 
smallFunction : function(index){ 

// Do Stuff! 

} 

Đối với hầu hết các phần này là tốt nhưng khi tôi xử lý mảng trên khoảng 1500 hoặc hơn, chúng tôi nhận được thông báo cảnh báo thực thi javascript.

Vì vậy, tôi cần phải giải quyết vấn đề này. Nỗ lực đầu tiên của tôi là như vậy:

longFunction : function(index){ 
     var self = this; 
     var data = self.data; 


     self.smallFunction(index); 

     if(data.slides[index+1){ 
     setTimeout(function(){ 
      self.longFunction(index+1); 
     },0); 
     } 
     else { 
       //WORK FINISHED 
     } 

}, 
smallFunction : function(index){ 

// Do Stuff! 

} 

Vì vậy, ở đây tôi loại bỏ vòng lặp và giới thiệu chức năng tự gọi làm tăng chỉ số của mỗi lần lặp. Để trả về điều khiển cho chuỗi giao diện người dùng chính để ngăn chặn phương thức cảnh báo thực thi javascript tôi đã thêm setTimeout để cho phép nó có thời gian cập nhật sau mỗi lần lặp lại. Vấn đề là với phương pháp này nhận được công việc thực tế thực hiện mất khá nghĩa là 10 lần lâu hơn. Những gì dường như đang xảy ra là mặc dù các setTimeout được thiết lập để 0, nó thực sự chờ đợi nhiều hơn như 10ms. mà trên mảng lớn xây dựng rất nhanh chóng. Loại bỏ các setTimeout và để cho longFunction gọi chính nó cho hiệu suất so sánh với phương pháp vòng lặp ban đầu.

Tôi cần giải pháp khác, một giải pháp có hiệu suất tương đương với vòng lặp nhưng không gây ra cảnh báo thực thi javascript. Thật không may webWorkers không thể được sử dụng trong trường hợp này.

Điều quan trọng cần lưu ý là tôi không cần UI hoàn toàn đáp ứng trong quá trình này. Chỉ cần đủ để cập nhật thanh tiến trình vài giây một lần.

Chia nhỏ thành các đoạn vòng có phải là một tùy chọn không? I E. thực hiện 500 lần lặp lại tại một thời điểm, dừng, thời gian chờ, cập nhật thanh tiến trình, thực hiện tiếp theo 500 vv .. vn ..

Có điều gì tốt hơn không?

ĐÁP:

Giải pháp duy nhất dường như được chunking công việc.

Bằng cách thêm dòng sau vào chức năng tự gọi điện thoại của tôi, tôi đang cho phép giao diện người dùng để cập nhật tất cả 250 lần lặp:

longFunction : function(index){ 
      var self = this; 
      var data = self.data; 


      self.smallFunction(index); 

      var nextindex = i+1; 

      if(data.slides[nextindex){ 
      if(nextindex % 250 === 0){ 
      setTimeout(function(){    
       self.longFunction(nextindex); 
      },0); 
      } 
      else { 
       self.longFunction(nextindex); 
      } 
      } 
      else { 
        //WORK FINISHED 
      } 

    }, 
    smallFunction : function(index){ 

    // Do Stuff! 

    } 

Tất cả tôi đang làm ở đây là kiểm tra nếu chỉ số tiếp theo là divisble 250, nếu nó là sau đó chúng tôi sử dụng thời gian chờ để cho phép chuỗi giao diện người dùng chính cập nhật. Nếu không, chúng tôi gọi lại trực tiếp. Đã giải quyết được vấn đề!

+0

Có thể chạy không đồng bộ trong nền không? Nếu bạn không thể làm điều đó, vâng, chia nó thành từng phần. – Patashu

+0

Chức năng chính xác của bạn là gì đối với mỗi mục? Có thể bạn có thể song song chúng bằng cách thực thi nhiều setTimeout cùng một lúc. – exebook

+1

@Patashu - công nhân web không có sẵn trong tất cả các trình duyệt ... Vì vậy, đột nhập vào đoạn hợp lý trông giống như cách tiếp cận an toàn. –

Trả lời

1

Dưới đây là một số mã trạm trộn sửa đổi từ một câu trả lời trước đó tôi đã viết:

var n = 0, 
    max = data.length; 
    batch = 100; 

(function nextBatch() { 
    for (var i = 0; i < batch && n < max; ++i, ++n) { 
     myFunc(n); 
    } 
    if (n < max) { 
     setTimeout(nextBatch, 0); 
    } 
})(); 
+0

Cả phương pháp của bạn và phương pháp tôi vừa thêm vào câu hỏi của tôi đều hoạt động hoàn hảo. Tôi mong đợi của bạn sẽ nhanh hơn một chút vì nó tránh được phí hoạt động. Cảm ơn alnitak. – gordyr

2

Trên thực tế 1500 timeout là không có gì, vì vậy bạn chỉ có thể làm điều này:

var i1 = 0 
for (var i = 0; i < 1500; i++) setTimeout(function() { doSomething(i1++) }, 0) 

Hệ thống sẽ xếp hàng các sự kiện thời gian chờ cho bạn và họ sẽ được gọi ngay lập tức cái khác. Và nếu người dùng nhấp vào bất kỳ điều gì trong quá trình thực thi, họ sẽ không nhận thấy bất kỳ sự chậm trễ nào. Và không có "kịch bản đang chạy quá lâu" điều.

Từ các thử nghiệm của tôi, V8 có thể tạo ra 500.000 thời gian chờ mỗi giây.

CẬP NHẬT

Nếu bạn cần i1 qua để chức năng lao động của bạn, chỉ cần vượt qua một đối tượng với nó, và tăng bộ đếm bên trong hàm của bạn.

function doSomething(obj) { 
    obj.count++ 
    ...put actual code here 
} 
var obj = {count: 0} 
for (var i = 0; i < 1500; i++) setTimeout(function() { doSomething(obj) }, 0) 

Dưới Node.js bạn cũng có thể sử dụng setImmediate(...).

+0

Trong khi đó chính xác nó làm chậm tất cả mọi thứ xuống ồ ạt kể từ khi chúng tôi đang sử dụng một thời gian chờ cho mỗi lần lặp. Trong hầu hết các trình duyệt, thời gian chờ 0 thực sự bằng khoảng 10ms có nghĩa là trong một bộ quy trình dài 2000, chúng tôi sẽ thêm 20 giây vào thời gian tải không cần thiết. Các giải pháp chúng tôi đã đưa ra chỉ chạy hết thời gian chờ tại một khoảng thời gian cụ thể cho phép những người khác kích hoạt ngay lập tức. – gordyr

+0

Tôi khá chắc chắn bạn không hiểu giải pháp này. setTimeouts sẽ bắt đầu tất cả cùng một lúc. Vài ms sẽ trôi qua trước khi người đầu tiên bắt đầu thực hiện. Nhưng những người khác sẽ làm theo nó mà không có bất kỳ sự chậm trễ. Bạn sẽ không nhận thêm 20 giây nữa. – exebook

+0

khi tôi nói 1500 thời gian chờ là không có gì, tôi không có nghĩa là 1500 * 10ms không phải là nhiều. Tôi có nghĩa là V8 có thể dễ dàng giữ một hàng đợi chờ hàng ngàn thời gian chờ, và thời gian của họ đã đến! vì vậy họ sẽ thực thi ngay lập tức từng cái một. – exebook

0

Có điều gì tốt hơn không?

Nếu bạn đồng ý với nó chỉ hoạt động trong trình duyệt hiện đại - thì bạn nên xem "Công nhân web", cho phép bạn thực thi JS ở chế độ nền.

https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers

+0

Tôi có rất nhiều kinh nghiệm với webworkers nhưng tiếc là họ không thể áp dụng cho tình huống này do hạn chế truy cập DOM do đó không thể được sử dụng. – gordyr

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