2012-01-08 40 views
10

如何實現在JavaScript中timeout,而不是window.timeout但類似session timeoutsocket timeout - 基本 - 一個「function timeout如何實現在JavaScript中的「功能超時」 - 不僅僅是「setTimeout的」

在指定事件發生之前,將在系統 中允許經過的特定時間段,除非另外指定的 事件首先發生;在任何一種情況下,當 發生任何事件時都會終止該期間。

具體來說,我想一個javascript observing timer將觀察函數的執行時間,如果達到或會超過規定時間,則observing timer將停止/通知執行功能。

任何幫助,非常感謝!非常感謝。

+0

['window.setTimeout(function_here,number_timeout_milliseconds)'](https://developer.mozilla.org/en/DOM/window.setTimeout)或'window.setInterval'? – 2012-01-08 15:29:24

+3

它不能完成,該功能將不會返回到任何東西,直到它完成。 – Esailija 2012-01-08 15:33:07

回答

12

我並不完全清楚你問什麼,但我認爲JavaScript不工作,你想的那麼它不能做的方式。例如,不能完成常規函數調用,直到操作完成或一段時間(以先到者爲準)。這可以在javascript之外實現,並通過javascript公開(如同步ajax調用一樣),但不能用純JavaScript和常規函數完成。

不像其他的語言,JavaScript是單線程的,這樣同時函數執行定時器將不會執行(除網絡工作者,但他們都非常,在他們能做什麼非常有限)。定時器只能在函數執行完成時執行。因此,甚至不能在同步函數和定時器之間共享進度變量,因此計時器無法「檢查」函數的進度。

如果你的代碼是完全獨立的(沒有訪問任何你的全局變量,沒打電話給你的其他功能,反正沒有訪問DOM),那麼你可以在Web的運行worker(僅在較新的瀏覽器中可用)並在主線程中使用計時器。當網絡工作者代碼完成時,它會將結果發送給主線程。當主線程收到該消息時,它停止定時器。如果計時器在收到結果之前觸發,它可能會殺死網絡工作者。但是,你的代碼必須忍受網絡工作者的限制。

Soemthing也可以用異步操作就像這樣(因爲他們與JavaScript的單線程岬更好的工作):

  1. 啓動異步操作像Ajax調用或圖像的加載。
  2. 使用setTimeout()您的超時時間開始計時。
  3. 如果你的異步操作之前,定時器觸發完成,然後停止異步操作(使用API​​來取消它)。
  4. 如果異步操作計時器觸發之前完成,則取消定時器clearTimeout()並繼續。

例如,這裏是如何把一個超時上的圖像的加載:

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

你可以做到這一點只能通過一些鐵桿的技巧。像例如,如果你知道什麼樣的變量的函數返回(注意:EVERY js函數返回的東西,默認爲undefined),你可以嘗試這樣的事:定義變量

var x = null; 

,並在單獨運行測試「線程「:

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); 

最後運行功能:

x = myFunction(myArguments); 

如果你知道這隻能你的函數不返回任何值(即返回的值是undefined)或者它返回的值總是「非假」,即不會被轉換爲false語句(如0,null等)。

+0

與其他語言不同,Javascript沒有可以與其他執行功能自由共享變量的線程。它有網絡工作者,但他們只能通過消息傳遞與主線程通信,而不能通過共享變量。 – jfriend00 2012-01-08 16:07:45

-1

observing timerexecuting function之間共享一個變量。

執行observing timerwindow.setTimeoutwindow.setInterval。當observing timer執行時,它將退出值設置爲共享變量。

executing function不斷檢查變量值..並返回出口值指定。

+1

'setTimeout'只保證最小延遲,如果執行函數在超時過期時仍在運行,只有在'執行函數'完成後纔會調用'觀察函數'。你需要實現一個JS版本的DoEvents來使這個解決方案有效。 – Douglas 2012-01-08 15:59:26

+0

執行函數運行時,定時器永遠不會被調用,因爲javascript是單線程的。定時器只能在函數執行完成後觸發。因此,我認爲這不可行。如果你認爲不然,請創建一個顯示這個的jsFiddle。 – jfriend00 2012-01-08 16:06:35

+0

你說得對。考慮一下,如果HTML5是一個選項,那麼使用工作者可能是一個可行的解決方案。你怎麼看? – 2012-01-08 16:19:12

2

您可以在web worker中執行代碼。然後,您仍然可以在代碼運行時處理超時事件。一旦網絡工作者完成工作,您可以取消超時。一旦超時發生,您可以終止網絡工作者。

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); 
    }); 
} 
相關問題