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

資訊專欄INFORMATION COLUMN

setTimeout與setInterval的區(qū)別和nodejs中的差異

meislzhua / 1351人閱讀

摘要:關(guān)于定時(shí)器的源碼在文件中,進(jìn)入就關(guān)于定時(shí)器的一些設(shè)計(jì)解釋,因?yàn)槭亲龇?wù)端代碼,在內(nèi)部等大部分事件都會創(chuàng)建一個(gè)定時(shí)器,任何時(shí)間都可能存在大量的定時(shí)器任務(wù),所以設(shè)計(jì)一個(gè)高效的定時(shí)器是很有必要的。

博客文章地址

setTimeout與setInterval

setTimeout setInterval 是我們在 javaScript 中經(jīng)常用到的定時(shí)器,setTimeout 方法用于在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式,setInterval 可按照指定的周期不停的調(diào)用函數(shù)或計(jì)算表達(dá)式。

但是當(dāng)我們要循環(huán)調(diào)用某任務(wù)時(shí)候,處了用 setInterval 指定周期外,我們也可以用函數(shù)中嵌套setTimeout 回掉自己來實(shí)現(xiàn), 可以看下面一段代碼

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

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

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

為了感受其中的差異,這里定義一個(gè)模擬任務(wù)執(zhí)行的函數(shù)

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

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

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

然后我們分別運(yùn)行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回掉),我們保證了每次進(jìn)程結(jié)束到下一次進(jìn)程開始的間隔為預(yù)期值,但是從每次進(jìn)程開始的時(shí)間間隔(我們這里精確到了秒)是會改變的,而B 方法(setInterval)表現(xiàn)的和我們預(yù)期的相同,正好與A相反。

nodejs中的差異

目前為止所以的表現(xiàn)都合理,至少很符合預(yù)期。可是當(dāng)我在 nodejs(v8.1.4) 中測試時(shí)候,卻發(fā)現(xiàn)不管我用 setTimeout 還是 setInterval ,他們總是能表現(xiàn)出同樣的效果(都是上面A方法的效果【用setTimeout回掉】)。這一點(diǎn)讓我很困惑,經(jīng)過一番探究,在 nodejs 關(guān)于 timers 的代碼中找到了答案。

nodejs 關(guān)于定時(shí)器的源碼在 node/lib/timer 文件中,進(jìn)入就關(guān)于定時(shí)器的一些設(shè)計(jì)解釋,因?yàn)?node 是做服務(wù)端代碼,在內(nèi)部 TCP, I/O.. 等大部分事件都會創(chuàng)建一個(gè)定時(shí)器,任何時(shí)間都可能存在大量的定時(shí)器任務(wù),所以設(shè)計(jì)一個(gè)高效的定時(shí)器是很有必要的。

nodejs實(shí)現(xiàn)定時(shí)器也很巧妙, 為了可以輕松取消添加事件,nodejs使用了雙向鏈表將 timer 插入和移除操作復(fù)雜度降低,具體實(shí)現(xiàn)在 node/lib/internal/linkedlist.js 文件中, 鏈表缺點(diǎn)自然是去查找元素,但是node ,把同一個(gè)時(shí)間間隔的 timer 維護(hù)在同一個(gè)雙向鏈表中,這樣就不需要去查找,因?yàn)橄炔迦氲目偸窍葓?zhí)行,具體的分析可以參考這篇文章 通過源碼解析 Node.js 中高效的 timer.

回歸主題,在 nodejs 關(guān)于 timer 的源碼下,我們可以找到執(zhí)行定時(shí)器的代碼

    // setInterval 會返回 createRepeatTimeout 的返回值
    exports.setInterval = function(callback, repeat, arg1, arg2, arg3) {
      ...
      return createRepeatTimeout(callback, repeat, args);
    }
    
    //  createRepeatTimeout函數(shù)生成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計(jì)算
      var timer = new Timeout(repeat, callback, args);
      timer._repeat = repeat; // 追加了_repeat屬性表示要循環(huán)調(diào)用
      ...
    
      return timer;
    }
    

    // 函數(shù)回掉時(shí),可以看到執(zhí)行時(shí)在ontimeout函數(shù)中
    function tryOnTimeout(timer, list) {
        ...
             try {
                ontimeout(timer);
                threw = false;
              } finally {
                if (timerAsyncId !== null) {
                  if (!threw)
                  ...
                }
        ...
    }
    
    // ontimeout執(zhí)行
    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);
    }

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

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

setTimeout interval should not include duration of callback

setInterval interval includes duration of callback

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

參考資料

nodejs源碼

setTimeout or setInterval?

JavaScript的setTimeout和setInterval的深入理解

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/88843.html

相關(guān)文章

  • JSNode.js中事件循環(huán)

    摘要:的單線程,與它的用途有關(guān)。特點(diǎn)的顯著特點(diǎn)異步機(jī)制事件驅(qū)動。隊(duì)列的讀取輪詢線程,事件的消費(fèi)者,的主角。它將不同的任務(wù)分配給不同的線程,形成一個(gè)事件循環(huán),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給引擎。 這兩天跟同事同事討論遇到的一個(gè)問題,js中的event loop,引出了chrome與node中運(yùn)行具有setTimeout和Promise的程序時(shí)候執(zhí)行結(jié)果不一樣的問題,從而引出了Nodejs的...

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

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

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

    摘要:事件觸發(fā)線程主要負(fù)責(zé)將準(zhǔn)備好的事件交給引擎線程執(zhí)行。它將不同的任務(wù)分配給不同的線程,形成一個(gè)事件循環(huán),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給引擎。 Fundebug經(jīng)作者浪里行舟授權(quán)首發(fā),未經(jīng)同意請勿轉(zhuǎn)載。 前言 本文我們將會介紹 JS 實(shí)現(xiàn)異步的原理,并且了解了在瀏覽器和 Node 中 Event Loop 其實(shí)是不相同的。 一、線程與進(jìn)程 1. 概念 我們經(jīng)常說 JS 是單線程執(zhí)行的,...

    TANKING 評論0 收藏0
  • 演示當(dāng)定時(shí)器在頁面最小化時(shí)無法執(zhí)行

      我們講述的是關(guān)于 ahooks 源碼系列文章的第七篇,總結(jié)主要講述下面幾點(diǎn):  鞏固 React hooks 的理解。  學(xué)習(xí)如何抽象自定義 hooks。構(gòu)建屬于自己的 React hooks 工具庫。  培養(yǎng)閱讀學(xué)習(xí)源碼的習(xí)慣,工具庫是一個(gè)對源碼閱讀不錯的選擇。  注:本系列對 ahooks 的源碼解析是基于v3.3.13。自己 folk 了一份源碼,主要是對源碼做了一些解讀,可見詳情。  ...

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

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

    Shisui 評論0 收藏0

發(fā)表評論

0條評論

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