亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

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

2019-11-20 14:16:07
字體:
來源:轉載
供稿:網友

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

復制代碼 代碼如下:

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

setTimeout(function() {

    document.write('<p>Hello there.</p>');

}, oneSecond);

而setInterval允許以指定的時間間隔重復執行函數。如果把下面的代碼注入到Web頁面,會導致每秒鐘向頁面文檔后面追加一句“Hello there”:

復制代碼 代碼如下:

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

                  setInterval(function() {

                                    document.write('<p>Hello there.</p>');

                  }, 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) {

                                     a ++;

                            }

                   });

                   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() {

                                     fs.unlink("/path/to/file");

                            });

                   });

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

假設,你打算設計一個叫my_async_function的函數,它可以做某些I/O操作(比如解析日志文件)的函數,并打算讓它周期性執行,你可以用setInterval這樣實現它:

復制代碼 代碼如下:

                   var interval = 1000;

                   setInterval(function() {

                            my_async_function(function() {

                                     console.log('my_async_function finished!');

                            });

                   },interval);//譯者注:前面“,interval”是我添加的,作者應該是筆誤遺漏了

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

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

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

復制代碼 代碼如下:

                   var interval = 1000;

                   setInterval(function(){

                            (function my_async_function(){

                                      setTimeout(function(){

                                              console.log("1");

                                      },5000);

                           })();

                   },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() {

                                     my_async_function(function() {      //第5行

                                               console.log('async is done!');

                                               schedule();

                                     });

                            }, 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()函數來回避這個棘手的問題。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人亚洲综合色就1024| 亚洲福利在线视频| 这里只有视频精品| 伊人伊成久久人综合网小说| 久久久久久国产精品久久| 国产va免费精品高清在线| 日本精品久久久| 国产成人avxxxxx在线看| 欧美在线观看一区二区三区| 欧美一级片在线播放| 亚洲精品第一页| 成人激情综合网| 精品一区二区三区四区在线| 国产精品视频免费在线观看| 成人精品视频久久久久| 青草青草久热精品视频在线网站| 久久久久久九九九| 午夜精品视频在线| 国产成人97精品免费看片| 国产精品18久久久久久麻辣| 91精品久久久久久久久| 日韩中文字幕欧美| 欧美专区在线视频| 欧美人与性动交a欧美精品| 国产精品美女久久久久久免费| 97精品国产97久久久久久免费| 亚洲综合日韩在线| 亚洲精品日韩久久久| www.欧美视频| 国产91对白在线播放| 欧美黄色成人网| 精品偷拍各种wc美女嘘嘘| 国产精品第一第二| 国产噜噜噜噜久久久久久久久| 欧美国产极速在线| 在线精品91av| 97视频在线观看视频免费视频| 搡老女人一区二区三区视频tv| 日韩电影免费观看中文字幕| 欧美日韩不卡合集视频| 欧美黄色性视频| 国产成人精品久久二区二区| 国产精品极品美女粉嫩高清在线| 国产精品观看在线亚洲人成网| 狠狠做深爱婷婷久久综合一区| 欧洲亚洲妇女av| 亚洲精选一区二区| 8050国产精品久久久久久| 91久久精品视频| 国产91精品久久久久| 中文日韩在线视频| 国产福利精品av综合导导航| 懂色av一区二区三区| 欧美裸体xxxx极品少妇软件| 国产日韩视频在线观看| 欧美大片第1页| y97精品国产97久久久久久| 亚洲欧美福利视频| 日本不卡高字幕在线2019| 国产精品嫩草影院久久久| 国语自产在线不卡| 日韩在线小视频| 日韩成人av网| 午夜精品在线视频| 成人免费福利视频| 欧美一级电影免费在线观看| 精品国产一区二区三区四区在线观看| 成人午夜激情免费视频| 在线不卡国产精品| 亚洲综合最新在线| 亚洲午夜精品久久久久久久久久久久| 国产精品专区一| 国产美女扒开尿口久久久| 亚洲欧美日韩久久久久久| 日韩专区在线播放| 亚洲精品在线91| 亚洲欧美激情一区| 在线电影中文日韩| www.欧美精品一二三区| 成人免费观看49www在线观看| 色七七影院综合| 欧美伊久线香蕉线新在线| 亚洲黄一区二区| 欧美尺度大的性做爰视频| 国产成人91久久精品| 欧美插天视频在线播放| 日韩高清欧美高清| 成人激情视频在线播放| 91国产美女在线观看| 国产裸体写真av一区二区| 操人视频在线观看欧美| 亚洲乱码国产乱码精品精天堂| 久久久久久国产三级电影| 欧美成人激情视频免费观看| 欧美激情欧美激情在线五月| 欧美日本高清一区| 一区二区三区美女xx视频| 少妇高潮久久久久久潘金莲| 青青久久av北条麻妃海外网| 亚洲视频在线免费观看| 亚洲成人网在线观看| 国产免费一区二区三区在线观看| 色播久久人人爽人人爽人人片视av| 一本大道久久加勒比香蕉| 久久五月天色综合| 亚洲天堂av在线播放| 国产精品爱久久久久久久| 国产色综合天天综合网| 性日韩欧美在线视频| 国产精品精品久久久久久| 国产精品中文久久久久久久| 美女精品久久久| 色噜噜亚洲精品中文字幕| 成人黄色午夜影院| 高清欧美性猛交xxxx| 黑人精品xxx一区一二区| 亚洲自拍欧美色图| 欧美理论在线观看| 中文字幕精品视频| 日本不卡高字幕在线2019| 51精品在线观看| 亚洲精品ady| 欧美激情精品久久久久久免费印度| 青草青草久热精品视频在线网站| 欧美在线性爱视频| 国产一区二区免费| 性欧美在线看片a免费观看| 亚洲国产精久久久久久久| 精品中文字幕视频| 国产日韩精品入口| 日韩av中文在线| 欧美日韩在线免费观看| 欧美黑人xxxx| 成人福利视频在线观看| 亚洲a∨日韩av高清在线观看| 日韩一级裸体免费视频| 一道本无吗dⅴd在线播放一区| 精品久久在线播放| 亚洲精品91美女久久久久久久| 日韩中文字幕在线看| 国产91精品久久久久| 亚洲欧美激情一区| 日韩精品免费在线观看| 亚洲国产精品va| 日韩美女中文字幕| 日本高清不卡的在线| 国模精品视频一区二区| 夜夜嗨av一区二区三区四区| 91社区国产高清| 欧美亚州一区二区三区| 亚洲欧美国产一区二区三区| 国产精品va在线播放我和闺蜜| 国产成人精品视频| 亚洲美女福利视频网站| 曰本色欧美视频在线| 国产精品久久久久一区二区| 国产精品视频一区二区三区四| 欧美激情亚洲自拍| 久久亚洲精品毛片| 国产婷婷成人久久av免费高清| 97精品国产97久久久久久免费| 国产精品啪视频| 日本免费久久高清视频| 国产精品高潮粉嫩av|