關于setTimeout & setInterval

前言

之所以寫這篇文章是因為上周工作中使用setInterval輪詢請求接口時遇到了一些問題订框,如果哪里理解的不對請大家多多指教~

進入正題

setTimeout和setInteval是window對象上兩個主要的定時方法,他們的語法基本相同,但完成功能的卻是不同的。
  • settimeout方法是定時程序兼丰,也就是在到達某個指定時間后灰粮,執(zhí)行什么事。(執(zhí)行一次就拉倒)
  • setinterval方法則是表示間隔一定時間反復執(zhí)行某些事蜈漓。
定時器的返回值
  • 當我們設置定時器時(不管是setTimeout還是setInterval),都會有一個返回值宫盔。這個返回值是一個數字融虽,代表當前是在瀏覽器中設置的第幾個定時器(返回的是定時器序號)。
      let timer1 = setTimeout(() => {
    
      }, 1000)
      console.log(timer1) // 1
    
      let timer2 = setInterval(() => {
    
      },1000)
      console.log(timer2) // 2
    
    • 根據上面兩端代碼可以知道
      • 1.setTimeout和setInterval雖然是處理不同功能的定時器灼芭,但都是瀏覽器的定時器有额,所以返回的序號是依次排列的。
      • 2.setInterval設置完成定時器會有一個返回值彼绷,不管執(zhí)行多少次巍佑,這個代表序號的返回值不變(設置定時器就有返回值,執(zhí)行多少次是定時器的處理)寄悯。
定時器的清除
  • clearTimeout([定時器的排隊序號])

  • clearInterval([定時器的排隊序號])

      let timer = setTimeout(() => {
        // 定時器即使清除了萤衰,其返回值也不會清除,之后設置定時器的返回值也會在其返回值的基礎上繼續(xù)向后排猜旬,
        // 類似于銀行的排隊領號脆栋,即使1號的業(yè)務辦理完了倦卖,后面的人仍是從2號開始繼續(xù)領號,而不是從1開始椿争。
        clearTimeout(timer)
      }, 1000)
    

注意: 定時器需要手動清除怕膛,并且clearTimeout和clearInterval都可以清除setTimeout或setInterval,但并不建議這樣做秦踪,容易造成混淆褐捻。

定時器的this指向
  • 作為第一個參數的函數將會在全局作用域中執(zhí)行,因此函數內的this將會指向這個全局對象
      let obj = {
        fn() {
          console.log(this) // obj
    
          // 示例1
          let timer1 = setTimeout(function() {
          
            console.log('我是timer1的this指向:', this)  // Window
          }, 1000)
    
          // 示例2 (讓定時器函數中的this是obj:使用變量保存的方式)
          let _this = this
          let timer2 = setTimeout(function() {
            console.log('我是timer2的this指向:', _this) // obj
          }, 1000)
    
          // 示例3 (讓定時器函數中的this是obj:使用bind方法改變this指針)
          let timer3 = setTimeout(
            function() {
              console.log('我是timer3的this指向:', this) // obj
            }.bind(this),
            1000
          )
    
          // 示例4 (讓定時器函數中的this是obj:使用箭頭函數椅邓,箭頭函數中的this繼承宿主環(huán)境(上級作用域中的this))
          let timer4 = setTimeout(() => {
            console.log('我是timer4的this指向:', this) // obj
          }, 1000)
        }
      }
      obj.fn()
    

setTimeout和setInterval是如何工作的柠逞?

涉及到的知識點:JS事件循環(huán)機制EVENTLOOP

  • 首先,Javascript是一門單線程的非阻塞的腳本語言:用來與瀏覽器交互希坚。
    • 單線程:同一時間只能執(zhí)行一個任務边苹,其他任務就得排隊,后續(xù)任務必須等到前一個任務結束才能開始執(zhí)行裁僧。
    • 非阻塞:同步任務直接在主線程隊列中順序執(zhí)行个束,而異步任務會進入另一個任務隊列,不會阻塞主線程聊疲。等到主線程隊列空了(執(zhí)行完了)的時候茬底,就會去異步隊列查詢是否有可執(zhí)行的異步任務了(異步任務通常進入異步隊列之后還要等一些條件才能執(zhí)行,如ajax請求获洲、文件讀寫)阱表,如果某個異步任務可以執(zhí)行了便加入主線程隊列,以此循環(huán)贡珊。

注意:異步任務之間并不相同最爬,他們的執(zhí)行優(yōu)先級有區(qū)別。不同的異步任務會被分為兩類:微任務(micro task)和宏任務(macro task)

  • 微任務:new promise()门岔,new MutaionObserver()
  • 宏任務:setInterval()爱致,setTimeout()
    主線程空閑的時候會先去查看微任務隊列是否有事件存在,如果存在就會對微任務隊列的事件依次調用寒随,直到為空糠悯。然后再對宏任務隊列依次執(zhí)行,進入循環(huán)妻往。
^ ^.png

使用定時器的時候互艾,千萬不要太相信預期,延遲的時間嚴格來說總是大于xxx毫秒的讯泣,至于大多少就要看當時執(zhí)行的情況了纫普。即使設置為0也不會馬上執(zhí)行,HTM5規(guī)范定最小延遲時間不能小于4ms好渠,不同瀏覽器的實現不一樣局嘁,比如溉箕,Chrome可以設置1ms晦墙,IE11/Edge是4ms悦昵。

setTimeout

setTimeout注冊的函數fn會交給瀏覽器的定時器模塊來管理,延遲時間到了就將fn加入主進程執(zhí)行隊列晌畅,如果隊列前面還有沒有執(zhí)行完的代碼但指,則又需要花一點時間等待才能執(zhí)行到fn,所以實際的延遲時間會比設置的長抗楔。如在fn之前正好有一個超級大循環(huán)棋凳,那延遲時間就不是一丁點了。

(function testSetTimeout() {
    console.time('timer');
    const timer = setTimeout(() => {
        console.timeEnd('timer');
    }, 10);
    for(let i = 0; i < 100000000; i++) {}
})();

// timer: 59.364990234375ms 遠遠不止10ms
setInterval

為什么盡量別用setInterval连躏?剩岳??

setInterval無視代碼錯誤

setInterval有個討厭的習慣入热,即對自己調用的代碼是否報錯這件事漠不關心拍棕,如果setInterval執(zhí)行的代碼由于某種原因出了錯,它還會持續(xù)不斷(不管不顧)地調用該代碼勺良。

function a() {
  try {
    cnosole.log('單詞拼寫錯誤,應該是console')
  } catch (e) {
    console.log('錯誤了')
  }
}
setInterval(a, 1000)

// 8VM69:5 錯誤了  (控制臺每間隔一秒就會輸出一個錯誤了) 
setInterval無視網絡延遲

假設你每隔一段時間就通過Ajax輪詢一次服務器绰播,看看有沒有新數據。而由于某些原因(服務器過載尚困、臨時斷網蠢箩、流量劇增、用戶帶寬受限事甜,等等谬泌,你的請求要花的時間遠比你想象的要長。但setInterval不在乎逻谦。它仍然會按定時持續(xù)不斷地觸發(fā)請求掌实,最終你的客戶端網絡隊列會塞滿Ajax調用。

例子:下面代碼并不是上一次fn執(zhí)行完了之后再過100ms才開始執(zhí)行下一次fn跨跨。 事實上潮峦,setInterval并不管上一次fn的執(zhí)行結果,而是每隔100ms就將fn放入異步隊列勇婴,而兩次fn之間具體間隔多久就不一定了忱嘹,跟setTimeout實際延遲時間類似,和JS執(zhí)行情況有關耕渴。

(function testSetInterval() {
    let i = 0;
    const start = Date.now();
    const timer = setInterval(() => {
        i++;
        i === 2 && clearInterval(timer);
        console.log(`第${i}次開始`, Date.now() - start);
        for(let i = 0; i < 900000000; i++) {}
        console.log(`第${i}次結束`, Date.now() - start);
    }, 100);
})();

VM232:7 第1次開始 104
VM232:9 第1次結束 603
VM232:7 第2次開始 605
VM232:9 第2次結束 1106

雖然每次fn執(zhí)行時間都很長拘悦,但下一次并不是等上一次執(zhí)行完了再過100ms才開始執(zhí)行的,實際上早就已經等在隊列里了橱脸。
在fn被阻塞的時候础米,setInterval仍然在組織將來對回調函數的調用分苇。 因此,當第一次fn函數調用結束時屁桑,已經有6次函數調用在等待執(zhí)行医寿。

處理可能的阻塞調用

最簡單也是最容易控制的方案,是在回調函數內部使用setTimeout函數蘑斧。

function foo(){
    setTimeout(foo, 100);
}
foo();
參考鏈接
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末靖秩,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子竖瘾,更是在濱河造成了極大的恐慌沟突,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捕传,死亡現場離奇詭異惠拭,居然都是意外死亡,警方通過查閱死者的電腦和手機庸论,發(fā)現死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門职辅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人葡公,你說我怎么就攤上這事罐农。” “怎么了催什?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵涵亏,是天一觀的道長。 經常有香客問我蒲凶,道長气筋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任旋圆,我火速辦了婚禮宠默,結果婚禮上,老公的妹妹穿的比我還像新娘灵巧。我一直安慰自己搀矫,他們只是感情好,可當我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布刻肄。 她就那樣靜靜地躺著瓤球,像睡著了一般。 火紅的嫁衣襯著肌膚如雪敏弃。 梳的紋絲不亂的頭發(fā)上卦羡,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天,我揣著相機與錄音,去河邊找鬼绿饵。 笑死欠肾,一個胖子當著我的面吹牛,可吹牛的內容都是我干的拟赊。 我是一名探鬼主播刺桃,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼要门!你這毒婦竟也來了虏肾?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤欢搜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谴轮,有當地人在樹林里發(fā)現了一具尸體炒瘟,經...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年第步,在試婚紗的時候發(fā)現自己被綠了疮装。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡粘都,死狀恐怖廓推,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情翩隧,我是刑警寧澤樊展,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布,位于F島的核電站堆生,受9級特大地震影響专缠,放射性物質發(fā)生泄漏。R本人自食惡果不足惜淑仆,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一涝婉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蔗怠,春花似錦墩弯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至怠惶,卻和暖如春涨缚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工脓魏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留兰吟,地道東北人。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓茂翔,卻偏偏與公主長得像混蔼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子珊燎,可洞房花燭夜當晚...
    茶點故事閱讀 43,576評論 2 349