2012-03-22 34 views
9

Tôi có một sự kiện có thể tự cháy. Tôi cố gắng làm cho mã hiệu quả nhất có thể, nhưng nó có thể đạt tới mức tối đa trong một số trường hợp, điều đó nằm ngoài tầm kiểm soát của tôi. Nó không phải là một ngăn xếp vô hạn và nó sẽ kết thúc tại một số điểm, nhưng đôi khi nó có khả năng có thể bị rơi trước khi nó kết thúc vì giới hạn.Làm cách nào để tăng số lượng cuộc gọi tối đa trong Javascript?

Tôi có tăng số lượng ngăn xếp cuộc gọi nếu tôi thiết lập 2 trình xử lý sự kiện tương tự và chia mã không? Hoặc tôi có thể làm gì?

CẬP NHẬT: Đó là sự kiện thay đổi DOM (chỉ làm việc với Webkit, vì vậy không quan tâm đến các trình duyệt khác), điều này cũng có thể sửa đổi DOM dựa trên một số điều kiện. Tôi chưa thực sự đạt đến giới hạn đó, nhưng về mặt lý thuyết, nó có khả năng có thể. Tôi vẫn đang tối ưu hóa mã để thực hiện các thao tác DOM ít nhất có thể.

UPDATE 2: Tôi bao gồm mẫu (không có thật) ví dụ:

document.addEventListener('DOMSubtreeModified', function(event){ 

    this.applyPolicy(event); 

}, true); 

function applyPolicy(event){ 
    if(typeof event != "undefined"){ 
     event.stopPropagation(); 
     event.stopImmediatePropagation(); 
    } 

    if(!isButtonAllowed){ 
     $('button:not(:disabled)').each(function(){ 

      $(this).attr('disabled', true); 

     }); 
    } 
} 

Đây chỉ là một mẫu mã, nhưng ngay cả trong trường hợp này, nếu bạn có nói 100s của nút, cuộc gọi stack cũng sẽ ở độ tuổi 100. Lưu ý rằng nếu bạn sử dụng $('button').attr('disabled', true);, điều này sẽ gây ra sự cố ngăn xếp cuộc gọi, vì jQuery sẽ cố gắng sửa đổi DOM vô hạn.

+1

Có lẽ bạn nên chuyển đổi hàm đệ quy thành vòng lặp '' while''? Tôi không thể tưởng tượng rằng bạn cần tác dụng phụ của hàng trăm nghìn sự kiện kích hoạt sự kiện thực sự để kích hoạt một số chức năng khác ... –

+1

Không bao giờ đạt đến giới hạn đó, nếu không phải khi mã hóa sai vòng lặp vô hạn. Hiển thị mã .. – gpasci

+2

Câu trả lời ngắn gọn: không có cơ chế (tiêu chuẩn) nào để thực hiện việc này. Tùy chọn duy nhất sau đó, là thay đổi mã. –

Trả lời

6

Trong khi có vẻ như bạn có thể cần phải suy nghĩ lại một số mã, một khả năng sẽ là đặt một cuộc gọi đệ quy trong một số setTimeout tại một số khoảng thời gian nhất định. Điều này cho phép bạn bắt đầu một ngăn xếp cuộc gọi mới.

Hãy ví dụ này ...

var i = 0; 

function start() { 
    ++i; 
    var is_thousand = !(i % 1000); 

    if (is_thousand) 
     console.log(i); 

    if (i >= 100000) 
     return; // safety halt at 100,000 
    else 
     start() 
} 

Nó chỉ đăng nhập vào giao diện điều khiển ở mọi khoảng thời gian 1,000. Trong Chrome, nó vượt quá ngăn xếp ở đâu đó trong phạm vi 30,000.

DEMO:http://jsfiddle.net/X44rk/


Nhưng nếu bạn làm lại nó như thế này ...

var i = 0; 

function start() { 
    ++i; 
    var is_thousand = !(i % 1000); 

    if (is_thousand) 
     console.log(i); 

    if (i >= 100000) // safety halt at 100,000 
     return; 
    else if (is_thousand) 
     setTimeout(start, 0); 
    else 
     start(); 
} 

Bây giờ ở mọi 1,000, hàm sẽ được phép quay trở lại và tiếp theo cuộc gọi sẽ được thực hiện không đồng bộ, bắt đầu một ngăn xếp cuộc gọi mới.

Lưu ý rằng điều này giả định rằng hàm được kết thúc hiệu quả khi thực hiện cuộc gọi đệ quy.

Cũng lưu ý rằng tôi có điều kiện để dừng tại 100,000 vì vậy chúng tôi không vô hạn.

DEMO:http://jsfiddle.net/X44rk/1/

+0

Điều này có vẻ thú vị. Tôi sẽ cho nó một shot. Cảm ơn! – Sherzod

+0

@shershams: Bạn được chào đón. Hãy cho tôi biết nếu bạn có thắc mắc. –

+1

Tôi đã thử mã của bạn với hàng triệu lần truy cập, nó vẫn hoạt động tốt. Tôi đang triển khai mã của mình bằng kỹ thuật này ngay bây giờ. Cảm ơn! – Sherzod

6

Đối với mọi trình duyệt, ngăn xếp cuộc gọi tối đa chạy tốt trong hàng nghìn. Bạn nên cố gắng tối ưu hóa mã, có một cuộc gọi ngăn xếp rất lớn là không tốt cho tốc độ và bộ nhớ.

Nếu bạn đang chạy vào điều này, nó là một chỉ số mã của bạn là thị trường hấp dẫn của tổ chức lại

+0

vấn đề là, sự kiện này đang lắng nghe sự thay đổi DOM và sau khi kiểm tra một số điều kiện, nó có thể thực sự sửa đổi DOM, điều này sẽ kích hoạt sự kiện đó một lần nữa. Do đó, ngăn xếp cuộc gọi có thể tăng khá nhanh. Tôi vẫn đang làm việc để tối ưu hóa mã để thực hiện các thao tác DOM ít nhất có thể. – Sherzod

+0

Vâng, đây là một nhận xét rất chung chung tôi biết .. nhưng bạn cần một sự tách biệt rõ ràng hơn về mối quan tâm. Nếu bạn nghe sự kiện domchange, điều đó có nghĩa là bạn dựa vào DOM của mình như một 'mô hình' hoặc 'mô hình xem'. Có rất nhiều điều sai trái với điều đó. Hãy thử triển khai backbone.js, ngay cả khi bạn không thích điều đó cụ thể .. bạn có thể học được rất nhiều từ các mẫu thiết kế giao diện người dùng tốt. – Evert

+0

Tôi đang sử dụng JavascriptMVC và jQuery. Cách duy nhất để giảm đệ quy trong trường hợp này là giảm số lượng thao tác DOM, do đó nó không tự cháy như vậy .. có cách nào tốt hơn không? – Sherzod

0

Kích thước của callstack và thực hiện chi tiết sẽ phụ thuộc vào môi trường mã JavaScript của bạn đang chạy trong. Thậm chí nếu bạn có thể thao tác sử dụng ngăn xếp để chạy trong các môi trường mà bạn quan tâm hiện nay, có khả năng là mã ngăn xếp đói sẽ sụp đổ khi chạy trong môi trường cung cấp kích thước ngăn xếp khác nhau.

Bất kỳ chương trình đệ quy nào cũng có thể được viết lại dưới dạng lặp lại. Hãy xem xét nếu bạn có thể làm điều đó trong trường hợp của bạn. Xem:

Way to go from recursion to iteration

0

Bạn không thể, họ là trình duyệt phụ thuộc và khá thẳng thắn họ có một phạm vi khá rộng, vì vậy không cần phải lo lắng về điều đó IMO.

0

Nếu bạn đang đạt đến giới hạn ngăn xếp cuộc gọi, bạn gần như chắc chắn có một loạt các sự kiện đệ quy. Sự kiện dựa trên một chồng, vì vậy chúng thực sự không phải là cách tốt nhất để thực hiện một vòng lặp. Trong một ngôn ngữ mà không cần loại bỏ cuộc gọi đuôi, lựa chọn thực sự duy nhất của bạn là sử dụng các cấu trúc vòng lặp chuẩn như for/in.

0

Sau khi phát hiện ra rằng bạn đang kiểm duyệt mã bên thứ ba có thể được render yếu tố mà bạn không muốn trả lại, tôi hiểu được vấn đề gốc thực: blacklists không bao giờ hoạt động trên mã không đáng tin cậy, cuối cùng một số mã sẽ vượt qua danh sách đen của bạn và bạn đã hoàn tất.

Bên ngoài rearchitecting mã của bạn như vậy mà không có mã của bên thứ ba hy vọng (hoặc được đưa ra) truy cập vào DOM, giải pháp của tôi sẽ như sau:

  1. Duplicate DOM của bạn thành một iframe ẩn.
  2. Sandbox mã của bên thứ ba trong iframe được cho biết.
  3. Trên bất kỳ thay đổi DOM nào trong iframe, hãy kiểm tra khung nội tuyến để biết sự khác biệt giữa hai cây DOM. Nếu thay đổi vượt qua danh sách trắng, hãy đưa nó vào DOM thực của bạn (gọi lại sự kiện đính kèm lại, v.v.).
  4. Sao chép cấu trúc của DOM "thực" sau khi cập nhật vào DOM khung nội tuyến, lọc mọi dữ liệu nhạy cảm khỏi nó trong quá trình.

Bạn vẫn sẽ kiểm tra sự kiện DOM trong khung nội tuyến, nhưng bạn sẽ không ở trong trang "thực sự" của mình, vì vậy bạn không thể nhập vòng lặp vô hạn.

Điều này giả định rằng bạn thực sự không thể tin tưởng mã bên thứ ba của bạn để làm những gì cần làm. Nếu nó chỉ là nhà cung cấp không đủ năng lực, hãy quên phần chà, nhưng gắn bó với danh sách trắng thay vì danh sách đen, dù sao đi nữa.

+0

Bản thân mã được phân tích bằng một tập lệnh khác trước khi xuất bản, nhưng nhà phát triển bên thứ ba có thể đã quên vô hiệu hóa một số thứ nhất định trên một số sự kiện, do đó, tôi cần kiểm tra và thực thi chính sách đó. Tôi chắc chắn sẽ cố gắng tạo ra một cái gì đó thực sự đơn giản bằng cách sử dụng phương pháp bạn đã đề cập. Ý tưởng về iframe nghe có vẻ thú vị, mặc dù tôi ghét họ. Cảm ơn! – Sherzod

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