2011-05-01 70 views
81

我想,一旦它被執行它在隊列中,但在隊列中有任何保證它會在X毫秒後精確調用?或者隊列中更高的任務會延遲嗎?setTimeout如何在Node.JS中工作?

+11

沒有非實時操作系統將永遠不可能有一個嚴重的準確性的保證。系統上的各種事情都會(並且會)阻礙定時器機制。 – Pointy 2011-05-01 15:09:29

回答

37

非阻塞的思想是循環迭代很快。所以迭代每個滴答時間應該足夠短一段時間,setTimeout將精確到合理的精度(可能是< 100 ms左右)。

雖然理論上你是對的。如果我編寫應用程序並阻止勾號,那麼setTimeouts將會延遲。所以要回答你的問題,誰可以保證setTimeouts按時執行?通過編寫非阻塞代碼,您可以控制幾乎任何合理程度的準確度。

只要javascript在代碼執行(不包括網絡工作者等)方面是「單線程」,那將會一直髮生。單線程本質在大多數情況下是一種巨大的簡化,但要求非阻塞式成語才能成功。

試試這個代碼出無論是在瀏覽器或節點,你會看到,有沒有準確的保證,相反,該setTimeout的將是非常晚:

var start = Date.now(); 

// expecting something close to 500 
setTimeout(function(){ console.log(Date.now() - start); }, 500); 

// fiddle with the number of iterations depending on how quick your machine is 
for(var i=0; i<5000000; ++i){} 

除非解釋優化循環(它不在chrome上),你會得到成千上萬的東西。刪除循環,你會看到它的鼻子上500 ...

6

確保執行代碼的唯一方法是將您的setTimeout邏輯放置在不同的過程中。

使用子進程模塊產生一個新的node.js程序,它執行你的邏輯並通過某種流(可能是tcp)將數據傳遞給該進程。

這種方式即使在你的主進程中運行了一些長的阻塞代碼,你的子進程已經自己啓動並將一個setTimeout放在一個新進程和一個新線程中,並在你期望的時候運行。

進一步的複雜性是在硬件級別,你有更多的線程運行,然後進程,因此上下文切換將導致(從很小的)延遲,從你的預期時間。這應該是微不足道的,如果重要的話,你需要認真考慮你想要做什麼,爲什麼你需要這樣的準確性,以及什麼樣的實時替代硬件可用來完成這項工作。

一般來說,使用子進程和多個節點應用程序作爲獨立進程與負載平衡器或共享數據存儲(如redis)一起運行對於擴展代碼非常重要。

131

setTimeout的語義與Web瀏覽器中的語義大致相同:超時參數爲最小值執行前要等待的毫秒數,而不是保證。此外,傳遞0,非數字或負數將導致它等待最小數量的ms。在節點中,這是1ms,但在瀏覽器中它可以高達50ms。

原因是JavaScript沒有搶佔JavaScript。考慮下面這個例子:

setTimeout(function() { 
    console.log('boo') 
}, 100) 
var end = Date.now() + 5000 
while (Date.now() < end) ; 
console.log('imma let you finish but blocking the event loop is the best bug of all TIME') 

這裏的流程是:

  1. 時間表超時100毫秒。
  2. 忙等待5000ms。
  3. 返回到事件循環。檢查掛起的定時器並執行。

如果情況並非如此,那麼您可能會有一點JavaScript「中斷」另一個。我們不得不建立互斥體和semaphors和這樣的,以防止這樣的代碼是非常難推理:

var a = 100; 
setTimeout(function() { 
    a = 0; 
}, 0); 
var b = a; // 100 or 0? 

節點的JavaScript執行的單threadedness使得它更簡單比大多數工作其他風格的併發。當然,這種權衡是因爲程序中一個不好表現的部分可能會以無限循環來阻止整個事物。

這是一個更好的惡魔戰鬥比複雜的搶先?那要看。

+6

你會得到一個非常準確的'console.log'消息的+1。 – 2017-05-01 05:17:26

3

setTimeout是一種線程,它保存給定時間的操作並執行。

setTimeout(function,time_in_mills); 

在這裏第一個參數應該是一個函數類型,aexample如果你要打印你的名字在3秒鐘後,你的代碼應該是下面llike。

setTimeout(function(){console.log('your name')},3000); 

關鍵poitn要記住的是,你要什麼都使用的setTimeout方法去做,做功能裏面。如果你想parcing一些參數,你的代碼來調用其他方法是類似於下,

setTimeout(function(){yourOtherMethod(parameter);},3000); 

快樂編碼的NodeJS :)

3

setTimeout(callback,t)至少使用後運行回調t毫秒。實際延遲取決於許多外部因素,如操作系統計時器粒度和系統負載。

因此,它有可能會在設定的時間後稍微調用,但以前不會調用。

計時器不能超過24.8天。