首頁 web前端 js教程 Node.js中使用計時器定時執行函數詳解_node.js

Node.js中使用計時器定時執行函數詳解_node.js

May 16, 2016 pm 04:39 PM
node.js 計時器

如果你熟悉客戶端JavaScript編程,你可能使用過setTimeout和setInterval函數,這兩個函數允許延時一段時間再運行函數。例如下面的程式碼, 一旦被載入到Web頁面,1秒後會在頁面文件後追加「Hello there」:

複製程式碼 程式碼如下:

var oneSecond = 1000 * 1; // one second = 1000 x 1 ms

setTimeout(function() {

    document.write('

Hello there.

');

}, oneSecond);

而setInterval允許以指定的時間間隔重複執行函數。如果把下面的程式碼注入到Web頁面,會導致每秒鐘在頁面文件後面追加一句「Hello there」:

複製程式碼 程式碼如下:

                  var oneSecond = 1000 * 1; // one second = 1000 x 1 ms

                  setInterval(function() {

                                  

                  }, oneSecond);


因為Web早已成為用來建立應用程式的平台,而不再是簡單的靜態頁面,所以這種類似的需求日益浮現。這些任務規劃函數可協助開發人員實現表單定期驗證,延遲遠端資料同步,或是需要延遲反應的UI互動。 Node也完整實作了這些方法。在伺服器端,你可以用它們來重複或延遲執行很多任務,例如快取過期,連接池清理,會話過期,輪詢等等。

使用setTimeout延遲函數執行

setTimeout可以製定一個在將來某個時間把指定函數運行一次的執行計劃,例如:

複製程式碼 程式碼如下:
                   var timeout_ms = 2000; // 2 seconds
                   var timeout = setTimeout(function() {

                            console.log("timed out!");

                   }, timeout_ms);


和客戶端JavaScript完全一樣,setTimeout接受兩個參數,第一個參數是需要被延遲的函數,第二個參數是延遲時間(以毫秒為單位)。

setTimeout回傳一個超時句柄,它是個內部對象,可以用它作為參數呼叫clearTimeout來取消計時器,除此之外這個句柄沒有任何作用。

使用clearTimeout取消執行計畫

一旦獲得了超時句柄,就可以用clearTimeout來取消函數執行計劃,像這樣:


複製程式碼 程式碼如下:
                   var timeoutTime = 1000; // one second
                   var timeout = setTimeout(function() {

                            console.log("timed out!");

                   }, timeoutTime);

                   clearTimeout(timeout);


 這個例子裡,計時器永遠不會被觸發,也不會輸出」time out!」這幾個字。你也可以在將來的任何時間取消執行計劃,就像下面的例子:

複製程式碼 程式碼如下:

 var timeout = setTimeout(function A() {
 
                            console.log("timed out!");
 
                   }, 2000);
 
                   setTimeout(function B() {
 
                            而clearTimeout(timeout);
 
                   }, 1000);

程式碼指定了兩個延遲執行的函數A和B,函數A計劃在2秒鐘後執行,B計劃在1秒鐘後執行,因為函數B先執行,而它取消了A的執行計劃,因此A永遠不會運作。

制定與取消函數的重複執行計畫

setInterval和setTimeout類似,但它會以指定時間為間隔重複執行一個函數。你可以用它來週期性的觸發一段程序,來完成一些類似清理,收集,日誌,獲取數據,輪詢等其它需要重複執行的任務。

下面程式碼每秒會向控制台輸出一句「tick」:

複製程式碼 程式碼如下:

                   var period = 1000; // 1 second

                   setInterval(function() {

                            console.log("tick");

                   }, period);

如果你不想讓它永遠運作下去,可以用clearInterval()取消計時器。

setInterval回傳一個執行計畫句柄,可以把它當作clearInterval的參數來取消執行計畫:

複製程式碼 程式碼如下:

                   var interval = setInterval(function() {

                            console.log("tick");

                   }, 1000);

                   // …

                   clearInterval(interval);

使用process.nextTick將函數執行延遲到事件循環的下一輪

有時客戶端JavaScript程式設計師用setTimeout(callback,0)將任務延遲一段很短的時間,第二個參數是0毫秒,它告訴JavaScript運行時,當所有掛起的事件處理完畢後立刻執行這個回調函數。有時候這種技術被用來延遲執行一些並不需要立刻執行的操作。例如,有時候需要在使用者事件處理完畢後再開始播放動畫或做一些其它的計算。

Node中,就像 「事件循環」的字面意思,事件循環運行在一個處理事件佇列的循環裡,事件循環工作過程中的每一輪就稱為一個tick。

你可以在事件循環每次開始下一輪(下一個tick)執行時調用回調函數一次,這也正是process.nextTick的原理,而setTimeout,setTimeout使用JavaScript運行時內部的執行隊列,而不是使用事件循環。

透過使用process.nextTick(callback) ,而不是setTimeout(callback, 0),你的回呼函數會在佇列內的事件處理完畢後立刻執行,它要比JavaScript的超時佇列快很多(以CPU時間來衡量)。

你可以像下面這樣,把函數延遲到下一輪事件循環再運行:

複製程式碼 程式碼如下:

                   process.nextTick(function() {

                           my_expensive_computation_function();

                   });

  注意:process物件是Node少數的全域物件之一。

阻塞事件循環

Node和JavaScript的執行時間採用的是單執行緒事件循環,每次循環,執行時透過呼叫相關回呼函數來處理佇列內的下個事件。當事件執行完畢,事件循環取得執行結果並處理下個事件,如此反复,直到事件隊列為空。如果其中一個回呼函數運行時佔用了很長時間,事件循環在那段時間就無法處理其它掛起的事件,這會讓應用程式或服務變得非常慢。

在處理事件時,如果使用了記憶體敏感或處理器敏感的函數,會導致事件循環變得緩慢,而且造成大量事件堆積,不能被及時處理,甚至堵塞隊列。

看下面阻塞事件循環的例子:

複製程式碼 程式碼如下:

                   process.nextTick(function nextTick1() {

                            var a = 0;

                            while(true) {

                                  

                            }

                   });

                   process.nextTick(function nextTick2() {

                            console.log("next tick");

                   });

                   setTimeout(function timeout() {

                            console.log("timeout");

                   }, 1000);


這個例子裡,nextTick2和timeout函數無論等待多久都沒機會運行,因為事件循環被nextTick函數裡的無限循環堵塞了,即使timeout函數被計劃在1秒鐘後執行它也不會運行。

         當使用setTimeout時,回呼函數會被加入到執行計畫佇列,而在這個例子裡它們甚至不會被加入到佇列。這雖然是個極端例子,但你可以看到,執行一個處理器敏感的任務時可能會堵塞或拖慢事件循環。

退出事件循環

使用process.nextTick,可以把一個非關鍵性的任務推遲到事件循環的下一輪(tick)再執行,這樣可以釋放事件循環,讓它可以繼續執行其它掛起的事件。

看下面例子,如果你打算刪除一個臨時文件,但是又不想讓data事件的回調函數等待這個IO操作,你可以這樣延遲它:


複製程式碼 程式碼如下:
                   stream.on("data", function(data) {
                           stream.end("my response");

                            process.nextTick(function() {

                                   

                            });

                   });


使用setTimeout取代setInterval來確保函數執行的串列性

假設,你打算設計一個叫my_async_function的函數,它可以做某些I/O操作(例如解析日誌檔)的函數,並打算讓它週期性執行,你可以用setInterval這樣實現它:

複製程式碼 程式碼如下:

                   var interval = 1000;

                   setInterval(function() {

                            my_async_function(function() {

                                   

                            });

                   },interval);//譯者註:前面「,interval」是我新增的,作者應該是錯誤遺漏了


你必須能確保這些函數不會同時執行,但是如果使用setinterval你無法保證這一點,假如my_async_function函數運行的時間比interval變數多了一毫秒,它們就會同時執行,而不是按次序串行執行。

譯者註:(下方粗體部分為譯者添加,非原書內容)

為了方便理解這部分內容,可以修改下作者的程式碼,讓它可以實際運作:

複製程式碼 程式碼如下:
                   var interval = 1000;
                   setInterval(function(){

                            (function my_async_function(){

                               

                                  

                                  

                           })();

                   },interval);

 運行下這段程式碼看看,你會發現,等待5秒鐘後,「hello 」被每隔1秒輸出一次。而我們期望是,當前my_async_function執行完畢(耗費5秒)後,等待1秒再執行下一個my_async_function,每次輸出之間應該間隔6秒才對。造成這種結果,是因為my_async_function不是串行執行的,而是多個在同時運行。

 因此,你需要一個辦法來強制使一個my_async_function執行結束到下個my_async_function開始執行之間的間隔時間正好是interval變數指定的時間。你可以這樣做:  


複製程式碼

程式碼如下:

                    var interval = 1000; // 1 秒

                   (function schedule() {      //第3行

                           以setTimeout(function do_it() {

                                  

                                  

                                  

                                  

                            }, interval);

                   }());        //第10排

 

前面程式碼裡,宣告了一個叫schedule的函數(第3行),並且在宣告後立刻呼叫它(第10行),schedule函數會在1秒(由interval指定)後執行do_it函式。 1秒鐘過後,第5行的my_async_function函數會被調用,當它執行完畢後,會調用它自己的那個匿名回調函數(第6行),而這個匿名回調函數又會再次重置do_it的執行計劃,讓它1秒鐘後重新執行,這樣程式碼就開始串行地不斷循環執行了。

小結

可以用setTimeout()函數預先設定函數的執行計劃,並用clearTimeout()函數取消它。也可以用setInterval()週期性的重複執行某個函數,對應的,可以使用clearInterval()取消這個重複執行計劃。 如果因為使用了一個處理器敏感的操作而堵塞了事件循環,那些原計劃應該被執行的函數將會被延遲,甚至永遠無法執行。所以不要在事件循環內使用CPU敏感的操作。還有,你可以用process.nextTick()把函數的執行延遲到事件循環的下一輪。

I/O和setInterval()一起使用時,你無法保證在任何時間點只有一個掛起的調用,但是,你可以使用遞歸函數和setTimeout()函數來迴避這個棘手的問題。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

在iPhone iOS 17上如何設定多個計時器 在iPhone iOS 17上如何設定多個計時器 Sep 18, 2023 am 09:01 AM

在iOS17中,您可以使用時鐘應用程式在iPhone上設定多個計時器,或使用Siri免持設定。我們在本文中討論了兩者。讓我們來看看它們。使用時鐘應用程式在iPhone上設定多個計時器打開iPhone上的時鐘應用程序,然後點擊右下角的計時器選項卡。現在,設定小時、分鐘和秒。您可以使用「標籤」和「計時器何時結束」選項來設定計時器的名稱以及計時器完成時的首選音調。這將幫助您區分計時器。完成後,點擊“開始”按鈕。然後,點擊右上角的「+」圖示。現在,重複上述步驟以在iPhone上設定多個計時器。您還可以瀏

圖文詳解Node V8引擎的記憶體和GC 圖文詳解Node V8引擎的記憶體和GC Mar 29, 2023 pm 06:02 PM

這篇文章帶大家深入了解NodeJS V8引擎的記憶體和垃圾回收器(GC),希望對大家有幫助!

如何在 iPhone 上使用多計時器與 iOS 17 如何在 iPhone 上使用多計時器與 iOS 17 Jun 21, 2023 am 08:18 AM

什麼是iOS17上的多計時器?在iOS17中,Apple現在為用戶提供了在iPhone上一次設定多個計時器的能力。這是一個可喜的變化,許多人多年來一直期待的變化。時鐘應用程式在iOS16之前只允許使用者一次設定一個計時器,現在可用於啟動任意數量的計時器,使其成為您一次完成多個任務的理想選擇。您可以在計時器畫面中設定任意數量的計時器。啟動計時器後,所有活動計時器都將在鎖定螢幕介面和通知中心顯示為「即時活動」通知。從這裡,您可以查看計時器關閉、暫停或停止計時器的剩餘時間,而無需打開時鐘應用程式。當您在時鐘

一文聊聊Node中的記憶體控制 一文聊聊Node中的記憶體控制 Apr 26, 2023 pm 05:37 PM

基於無阻塞、事件驅動建立的Node服務,具有記憶體消耗低的優點,非常適合處理海量的網路請求。在海量請求的前提下,就需要考慮「記憶體控制」的相關問題了。 1. V8的垃圾回收機制與記憶體限制 Js由垃圾回收機

聊聊如何選擇一個最好的Node.js Docker映像? 聊聊如何選擇一個最好的Node.js Docker映像? Dec 13, 2022 pm 08:00 PM

選擇一個Node的Docker映像看起來像是小事,但是映像的大小和潛在漏洞可能會對你的CI/CD流程和安全造成重大的影響。那我們要如何選擇一個最好Node.js Docker映像呢?

windows7計時器位置介紹 windows7計時器位置介紹 Jul 08, 2023 pm 11:53 PM

windows7計時器在哪裡,有些客戶使用win7時想要知道win7的倒數計時在哪裡,其實win7沒有自帶的計時器,但是有時鐘能夠記時,那麼下面就是有關windows7計時器位置介紹,最先根據個性化打開,隨後找到任務列和選單列的選項中,接著與謳歌自定,找到時鐘,選擇打開,這樣就能夠根據時鐘進行到技術了。非常的簡單迅速。 windows7計時器在哪裡在電腦螢幕空白,滑鼠右鍵,選擇開啟」個人化」。選擇開啟」工作列和功能表列」選項,開啟後,我們在任務欄的頁籤裡,下方有個狀態列地區,點擊自定按鍵點擊下面的」打

深入聊聊Node中的File模組 深入聊聊Node中的File模組 Apr 24, 2023 pm 05:49 PM

文件模組是對底層文件操作的封裝,例如文件讀寫/打開關閉/刪除添加等等文件模組最大的特點就是所有的方法都提供的**同步**和**異步**兩個版本,具有sync 字尾的方法都是同步方法,沒有的都是異

聊聊Node.js中的 GC (垃圾回收)機制 聊聊Node.js中的 GC (垃圾回收)機制 Nov 29, 2022 pm 08:44 PM

Node.js 是如何做 GC (垃圾回收)的?下面這篇文章就來帶大家了解一下。

See all articles