国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

setTimeout與setInterval的區別和nodejs中的差異

meislzhua / 1364人閱讀

摘要:關于定時器的源碼在文件中,進入就關于定時器的一些設計解釋,因為是做服務端代碼,在內部等大部分事件都會創建一個定時器,任何時間都可能存在大量的定時器任務,所以設計一個高效的定時器是很有必要的。

博客文章地址

setTimeout與setInterval

setTimeout setInterval 是我們在 javaScript 中經常用到的定時器,setTimeout 方法用于在指定的毫秒數后調用函數或計算表達式,setInterval 可按照指定的周期不停的調用函數或計算表達式。

但是當我們要循環調用某任務時候,處了用 setInterval 指定周期外,我們也可以用函數中嵌套setTimeout 回掉自己來實現, 可以看下面一段代碼

    // A
    function myTimeout() {
        doStuff()
        setTimeout(myTimeout, 1000)
    }
    myTimeout()
    
    // B
    function myTimeout() {
        doStuff()
    }
    myTimeout()
    setInterval(myTimeout, 1000)

上面A, B 兩個方法都是在循環執行 myTimeout 函數,可是它們之間有什么不同呢。我們大部分都知道這其實取決與 doStuff 所消耗的時間, 如下圖所示如果 doStuff 消耗時間很短(實際中大部分消耗時間都很短很難有所察覺),兩個方法效果近似

doStuff是一個很復雜的計算,需要消耗很長時間時候,我們就可以分析出A 方法(用setTimeout回掉)能夠保障每一次任務結束到下一次任務開始的時間間隔為我們預期的值,但是B(setInterval)卻能保證任務開始到下一次任務開始之間的間隔為我們預期的值,(當然如果doStuff執行時間比我們預期間隔還長,setInterval 還有可能會直接放棄某次任務,這種罕見情況我們暫不考慮)

為了感受其中的差異,這里定義一個模擬任務執行的函數

    function wait(time) {
        var start = Date.now()
        while(Date.now() - start < time){}
    }

wait什么也沒做,但是卻可以阻塞進程time毫秒的時間,然后我們定義 doStuff,讓它每次執行阻塞進程500ms,而且可以輸出間隔時間信息,以及本次執行結束到下次執行開始的時間間隔

    function doStuff() {
        console.log("doStuff___start", new Date().getSeconds()) //每次輸出當前的秒數
            
        console.timeEnd("timeout") //每次輸出這次執行與上一次執行結束的時間間隔
        wait(500)
        console.time("timeout")
    }

然后我們分別運行A, B兩種方法

    /*
     * A方法 setTimeout
     */
    // doStuff___start 36
    // timeout: 1002.865966796875ms
    // doStuff___start 37
    // timeout: 1004.380859375ms
    // doStuff___start 39
    // timeout: 1001.550048828125ms
    // doStuff___start 40
    // timeout: 1001.051025390625ms
    // doStuff___start 42
    // timeout: 1001.637939453125ms
    
    /*
     * B方法 setInterval
     */
    // doStuff___start 50
    // timeout: 500.412109375ms
    // doStuff___start 51
    // timeout: 500.51806640625ms
    // doStuff___start 52
    // timeout: 500.099853515625ms
    // doStuff___start 53
    // timeout: 499.873291015625ms
    // doStuff___start 54
    // timeout: 500.439697265625ms
    

可以看到 A 方法(用setTimeout回掉),我們保證了每次進程結束到下一次進程開始的間隔為預期值,但是從每次進程開始的時間間隔(我們這里精確到了秒)是會改變的,而B 方法(setInterval)表現的和我們預期的相同,正好與A相反。

nodejs中的差異

目前為止所以的表現都合理,至少很符合預期??墒钱斘以?nodejs(v8.1.4) 中測試時候,卻發現不管我用 setTimeout 還是 setInterval ,他們總是能表現出同樣的效果(都是上面A方法的效果【用setTimeout回掉】)。這一點讓我很困惑,經過一番探究,在 nodejs 關于 timers 的代碼中找到了答案。

nodejs 關于定時器的源碼在 node/lib/timer 文件中,進入就關于定時器的一些設計解釋,因為 node 是做服務端代碼,在內部 TCP, I/O.. 等大部分事件都會創建一個定時器,任何時間都可能存在大量的定時器任務,所以設計一個高效的定時器是很有必要的。

nodejs實現定時器也很巧妙, 為了可以輕松取消添加事件,nodejs使用了雙向鏈表將 timer 插入和移除操作復雜度降低,具體實現在 node/lib/internal/linkedlist.js 文件中, 鏈表缺點自然是去查找元素,但是node ,把同一個時間間隔的 timer 維護在同一個雙向鏈表中,這樣就不需要去查找,因為先插入的總是先執行,具體的分析可以參考這篇文章 通過源碼解析 Node.js 中高效的 timer.

回歸主題,在 nodejs 關于 timer 的源碼下,我們可以找到執行定時器的代碼

    // setInterval 會返回 createRepeatTimeout 的返回值
    exports.setInterval = function(callback, repeat, arg1, arg2, arg3) {
      ...
      return createRepeatTimeout(callback, repeat, args);
    }
    
    //  createRepeatTimeout函數生成timer
    function createRepeatTimeout(callback, repeat, args) {
      repeat *= 1; // coalesce to number or NaN
      if (!(repeat >= 1 && repeat <= TIMEOUT_MAX))
        repeat = 1; // 這里間隔如果小于1或者大于TIMEOUT_MAX(2^31-1)都會按照1計算
      var timer = new Timeout(repeat, callback, args);
      timer._repeat = repeat; // 追加了_repeat屬性表示要循環調用
      ...
    
      return timer;
    }
    

    // 函數回掉時,可以看到執行時在ontimeout函數中
    function tryOnTimeout(timer, list) {
        ...
             try {
                ontimeout(timer);
                threw = false;
              } finally {
                if (timerAsyncId !== null) {
                  if (!threw)
                  ...
                }
        ...
    }
    
    // ontimeout執行
    function ontimeout(timer) {
      var args = timer._timerArgs;
      var callback = timer._onTimeout;
      if (typeof callback !== "function")
        return promiseResolve(callback, args[0]);
      if (!args)
        timer._onTimeout();
      else {
        switch (args.length) {
          case 1:
            timer._onTimeout(args[0]);
            break;
          case 2:
            timer._onTimeout(args[0], args[1]);
            break;
          case 3:
            timer._onTimeout(args[0], args[1], args[2]);
            break;
          default:
            Function.prototype.apply.call(callback, timer, args);
        }
      }
      if (timer._repeat) // 追加timer
        rearm(timer);
    }

上面代碼分析,可以看到追加循環調用是在 ontimeout 函數中,它里面一大堆判斷參數個數的內容可以不管,最后的if(timer._repeat) rearm(timer)判斷是否要循環調用,可以看到它是在上面 timer._onTimeout 執行完之后才去執行的。這和我們開始寫的A方法(用setTimeout回掉)基本類似,至此在 nodejs 表現出的不同就可以理解了。

issues , 關于這個問題也有很多討論,還是有不少人想把它改會我們熟悉的方式的

setTimeout interval should not include duration of callback

setInterval interval includes duration of callback

具體最后要怎樣還是要看后面的版本修改了。

參考資料

nodejs源碼

setTimeout or setInterval?

JavaScript的setTimeout和setInterval的深入理解

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/88843.html

相關文章

  • JSNode.js中事件循環

    摘要:的單線程,與它的用途有關。特點的顯著特點異步機制事件驅動。隊列的讀取輪詢線程,事件的消費者,的主角。它將不同的任務分配給不同的線程,形成一個事件循環,以異步的方式將任務的執行結果返回給引擎。 這兩天跟同事同事討論遇到的一個問題,js中的event loop,引出了chrome與node中運行具有setTimeout和Promise的程序時候執行結果不一樣的問題,從而引出了Nodejs的...

    abson 評論0 收藏0
  • 理解javascript中事件循環(Event Loop)

    摘要:主線程會暫時存儲等異步操作,直接向下執行,當某個異步事件觸發時,再通知主線程執行相應的回調函數,通過這種機制,避免了單線程中異步操作耗時對后續任務的影響。 背景 在研究js的異步的實現方式的時候,發現了JavaScript 中的 macrotask 和 microtask 的概念。在查閱了一番資料之后,對其中的執行機制有所了解,下面整理出來,希望可以幫助更多人。 先了解一下js的任務執...

    mykurisu 評論0 收藏0
  • 瀏覽器Node事件循環(Event Loop)有何區別?

    摘要:事件觸發線程主要負責將準備好的事件交給引擎線程執行。它將不同的任務分配給不同的線程,形成一個事件循環,以異步的方式將任務的執行結果返回給引擎。 Fundebug經作者浪里行舟授權首發,未經同意請勿轉載。 前言 本文我們將會介紹 JS 實現異步的原理,并且了解了在瀏覽器和 Node 中 Event Loop 其實是不相同的。 一、線程與進程 1. 概念 我們經常說 JS 是單線程執行的,...

    TANKING 評論0 收藏0
  • 演示當定時器在頁面最小化時無法執行

      我們講述的是關于 ahooks 源碼系列文章的第七篇,總結主要講述下面幾點:  鞏固 React hooks 的理解?! W習如何抽象自定義 hooks。構建屬于自己的 React hooks 工具庫?! ∨囵B閱讀學習源碼的習慣,工具庫是一個對源碼閱讀不錯的選擇?! ∽ⅲ罕鞠盗袑?ahooks 的源碼解析是基于v3.3.13。自己 folk 了一份源碼,主要是對源碼做了一些解讀,可見詳情?! ?..

    3403771864 評論0 收藏0
  • JavaScript單線程事件循環(Event Loop)那些事

    摘要:概述本篇主要介紹的運行機制單線程事件循環結論先在中利用運行至完成和非阻塞完成單線程下異步任務的處理就是先處理主模塊主線程上的同步任務再處理異步任務異步任務使用事件循環機制完成調度涉及的內容有單線程事件循環同步執行異步執行定時器的事件循環開始 1.概述 本篇主要介紹JavaScript的運行機制:單線程事件循環(Event Loop). 結論先: 在JavaScript中, 利用運行至...

    Shisui 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<