2012-01-08 32 views
10

Làm thế nào để thực hiện một timeout trong Javascript, không phải là window.timeout nhưng cái gì đó như session timeout hoặc socket timeout - cơ bản - một "function timeout"Làm thế nào để thực hiện một "chức năng timeout" trong Javascript - không chỉ là 'setTimeout'

Khoảng thời gian được chỉ định sẽ được phép trôi qua trong hệ thống trước khi xảy ra sự kiện được chỉ định, trừ khi một sự kiện khác được chỉ định xảy ra trước; trong cả hai trường hợp, khoảng thời gian được chấm dứt khi sự kiện diễn ra.

Cụ thể, tôi muốn có một javascript observing timer rằng sẽ quan sát thời gian thực hiện một chức năng và nếu đạt hoặc đi hơn một thời gian nhất định thì observing timer sẽ dừng/thông báo cho chức năng thực hiện.

Bất kỳ trợ giúp nào được đánh giá cao! Cảm ơn rất nhiều.

+0

[ 'window.setTimeout (function_here, number_timeout_milliseconds)'] (https://developer.mozilla.org/en/DOM/window.setTimeout) hoặc 'window.setInterval'? –

+3

Nó không thể được thực hiện, chức năng sẽ không trở lại kiểm soát bất cứ điều gì cho đến khi nó được hoàn thành. – Esailija

Trả lời

12

Tôi không hoàn toàn rõ ràng những gì bạn đang yêu cầu, nhưng tôi nghĩ rằng Javascript không hoạt động theo cách bạn muốn để nó không thể được thực hiện. Ví dụ, nó không thể được thực hiện mà một cuộc gọi chức năng thường xuyên kéo dài cho đến khi hoạt động hoàn thành hoặc một số tiền nhất định của thời gian nào đến trước. Điều đó có thể được thực hiện bên ngoài javascript và tiếp xúc thông qua javascript (như được thực hiện với các cuộc gọi ajax đồng bộ), nhưng không thể được thực hiện trong javascript thuần túy với các chức năng thông thường.

Không giống như các ngôn ngữ khác, Javascript là chuỗi đơn để trong khi chức năng đang thực hiện bộ hẹn giờ sẽ không bao giờ thực thi (ngoại trừ công nhân web, nhưng chúng rất, rất hạn chế trong những gì họ có thể làm). Bộ hẹn giờ chỉ có thể thực hiện khi hàm kết thúc thực thi. Vì vậy, bạn thậm chí không thể chia sẻ một biến tiến bộ giữa một chức năng đồng bộ và một bộ hẹn giờ vì vậy không có cách nào cho một bộ đếm thời gian để "kiểm tra" tiến độ của một hàm.

Nếu mã của bạn hoàn toàn độc lập (không truy cập bất kỳ biến toàn cầu nào của bạn, không gọi các chức năng khác của bạn và không truy cập DOM), thì bạn có thể chạy nó trên web- nhân viên (chỉ có trong các trình duyệt mới hơn) và sử dụng bộ hẹn giờ trong chuỗi chính. Khi mã công nhân web hoàn thành, nó sẽ gửi một thông báo đến luồng chính với kết quả của nó. Khi chủ đề chính nhận được tin nhắn đó, nó sẽ dừng hẹn giờ. Nếu bộ đếm thời gian kích hoạt trước khi nhận kết quả, nó có thể giết chết nhân viên web. Tuy nhiên, mã của bạn sẽ phải sống với những hạn chế của công nhân web.

soemthing cũng có thể được thực hiện với các hoạt động không đồng bộ (vì họ làm việc tốt hơn với single-ren-Ness Javascript của) như thế này:

  1. Bắt đầu một hoạt động không đồng bộ như một cuộc gọi ajax hoặc tải một hình ảnh.
  2. Bắt đầu hẹn giờ bằng cách sử dụng setTimeout() cho thời gian chờ của bạn.
  3. Nếu bộ hẹn giờ kích hoạt trước khi hoạt động không đồng bộ của bạn hoàn tất, hãy dừng hoạt động không đồng bộ (sử dụng API để hủy nó).
  4. Nếu hoạt động không đồng bộ hoàn tất trước khi hẹn giờ kích hoạt, sau đó hủy hẹn giờ với clearTimeout() và tiếp tục.

Ví dụ, dưới đây là cách đặt một thời gian chờ trên tải một hình ảnh:

function loadImage(url, maxTime, data, fnSuccess, fnFail) { 
    var img = new Image(); 

    var timer = setTimeout(function() { 
     timer = null; 
     fnFail(data, url); 
    }, maxTime); 

    img.onLoad = function() { 
     if (timer) { 
      clearTimeout(timer); 
      fnSuccess(data, img); 
     } 
    } 

    img.onAbort = img.onError = function() { 
     clearTimeout(timer); 
     fnFail(data, url); 
    } 
    img.src = url; 
} 
1

Bạn có thể đạt được điều này chỉ sử dụng một số thủ thuật hardcore.Ví dụ như nếu bạn biết những gì loại biến trở về chức năng của bạn (lưu ý rằng MỌI js chức năng trả về một cái gì đó, mặc định là undefined), bạn có thể thử một cái gì đó như thế này: xác định biến

var x = null; 

và chạy thử nghiệm trong riêng biệt " chủ đề ":

function test(){ 
    if (x || x == undefined) 
     console.log("Cool, my function finished the job!"); 
    else 
     console.log("Ehh, still far from finishing!"); 
} 
setTimeout(test, 10000); 

và chức năng cuối cùng chạy:

x = myFunction(myArguments); 

chỉ này hoạt động nếu bạn biết chức năng của bạn không trả về bất kỳ giá trị nào (tức là giá trị trả về là undefined) hoặc giá trị trả về luôn "không sai", tức là không được chuyển đổi thành câu hỏi false (như 0, null, v.v ...).

+0

Không giống như các ngôn ngữ khác, Javascript không có chủ đề có thể tự do chia sẻ các biến với các hàm thực thi khác. Nó có công nhân web, nhưng họ chỉ có thể giao tiếp với chủ đề chính thông qua nhắn tin chứ không phải bằng cách chia sẻ các biến. – jfriend00

-1

Chia sẻ biến giữa observing timerexecuting function.

Triển khai observing timer với window.setTimeout hoặc window.setInterval. Khi thực hiện observing timer, nó đặt giá trị thoát cho biến được chia sẻ.

executing function liên tục kiểm tra giá trị biến .. và trả về nếu giá trị thoát được chỉ định.

+1

'setTimeout' chỉ đảm bảo độ trễ tối thiểu, nếu' chức năng thực hiện' vẫn đang chạy khi hết thời gian chờ, hàm 'quan sát' sẽ chỉ được gọi khi hàm' thi hành' hoàn tất. Bạn sẽ cần phải thực hiện một phiên bản JS của 'DoEvents' để làm cho giải pháp này hoạt động. – Douglas

+0

Một bộ hẹn giờ sẽ không bao giờ được gọi trong khi một hàm thực thi đang chạy vì javascript là một luồng đơn. Bộ hẹn giờ CHỈ có thể được kích hoạt sau khi chức năng kết thúc thực thi. Vì vậy, tôi không nghĩ rằng điều này có thể làm việc. Nếu bạn nghĩ cách khác, hãy tạo một jsFiddle cho thấy điều này. – jfriend00

+0

Bạn nói đúng. Suy nghĩ về nó, nếu HTML5 là một lựa chọn, việc sử dụng một công nhân có thể là một giải pháp khả thi. Bạn nghĩ sao? –

2

Bạn có thể thực thi mã trong công nhân web. Sau đó, bạn vẫn có thể xử lý các sự kiện hết thời gian chờ khi mã đang chạy. Ngay khi nhân viên web hoàn thành công việc của mình, bạn có thể hủy thời gian chờ. Và ngay sau khi thời gian chờ xảy ra, bạn có thể chấm dứt nhân viên web.

execWithTimeout(function() { 
    if (Math.random() < 0.5) { 
     for(;;) {} 
    } else { 
     return 12; 
    } 
}, 3000, function(err, result) { 
    if (err) { 
     console.log('Error: ' + err.message); 
    } else { 
     console.log('Result: ' + result); 
    } 
}); 

function execWithTimeout(code, timeout, callback) { 
    var worker = new Worker('data:text/javascript;base64,' + btoa('self.postMessage(' + String(code) + '\n());')); 
    var id = setTimeout(function() { 
     worker.terminate(); 
     callback(new Error('Timeout')); 
    }, timeout); 
    worker.addEventListener('error', function(e) { 
     clearTimeout(id); 
     callback(e); 
    }); 
    worker.addEventListener('message', function(e) { 
     clearTimeout(id); 
     callback(null, e.data); 
    }); 
} 
Các vấn đề liên quan