關於setTimeout

面試官:「你知道定時器嗎?」
我:「知道」
面試官:「那你說說什麼是定時器」
我:「定時器是能夠用setTimeout來實現的」
面試官:「setTimeout(function () { console.log("1") },0);
console.log("2");那你說說控制檯上輸出順序是什麼?」
我:支支吾吾......

so....就有了這篇文章,嘮叨了這麼久,正文開始了!

setTimeout的語法功能:

setTimeout() 方法用於在指定的毫秒數後調用函數或計算表達式

爲了解釋上面的那句話,來個簡單的小例子:javascript

<!DOCTYPE html>
<head>
    <title>setTimeout</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
    <h1>setTimeout</h1>
    <span id="content">測試</span>
    <script>
       setTimeout(function () {
           let content = document.getElementById('content');
           content.innerHTML = "<div>一秒後</div>";
       },1000);
    </script>
</body>
</html>
複製代碼

span標籤裏面的內容一秒以後由「測試」變成了「一秒後」。html

記時器功能:

來實現了:java

<!DOCTYPE html>
<head>
    <title>setTimeout</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
    <h1>setTimeout</h1>
    <span id="content">時間</span>
    <button onclick="start()">開始</button>
    <script>
        var x = 00,
            y = 00,
            z = 00;
        function start () {
            if (x<= 59 && x>=0 && y<=59 && y>=0 && z<=59 && z>=0) {
               let content = document.getElementById('content');
               content.innerHTML = z + ":" + y + ":" + x;
               console.log(x);
               x = x + 1;
            } else if (y<=59 && y>=0 && z<=59 && z>=0) {
                y = y + 1;
                x = 0;
            } else if (z<=59 && z>=0){
                z = z + 1;
                x = 0;
                y = 0;
            }
            setTimeout ("start()",1000);  //注意,這裏調用要用引號包圍
        }
    </script>
</body>
</html>
複製代碼

控制檯輸出: 面試

這裏點擊以後執行start()函數,在函數裏面setTimeout()函數又調用了start(),因此就是一秒鐘調用一次start()函數。ajax

setTimeout()的參數:

你們都知道setInterval()和setTimeout()能夠接收兩個參數,第一個參數是須要回調的函數,必須傳入的參數,第二個參數是時間間隔,毫秒數,能夠省略。但其實他能夠接收更多的參數,那麼這些參數是幹什麼用的呢?從第三個參數開始,依次用來表示傳入回調函數的參數。瀏覽器

例子:bash

setTimeout(function(a,b){
   console.log(0+a+b);//這裏打印的是:7
},1000,3,4);
複製代碼
注意:IE 9.0及如下版本,只容許setTimeout有兩個參數,不支持更多的參數

若是想向回調函數傳參,能夠用bind()。
eg:異步

setTimeout( function(a,b){}.bind(3,4), 1000 );
複製代碼
那我怎麼去除定時器呢(惆悵臉)?別急,別急,我來告訴你!

clearTimeout():

setTimeout函數,返回一個表示計數器編號的整數值,將該整數傳入clearTimeout函數,就能夠取消對應的定時器。函數

clearTimout()有如下語法: clearTimeout(timeoutID)
要使用 clearTimeout( ), 咱們設定 setTimeout( ) 時, 要給予這 setTimout( ) 一個名稱, 這名稱就是 timeoutID , 咱們叫停時, 就是用這 timeoutID來叫停, 這是一個自定義名稱。oop

用法:

var id1 = setTimeout(f,1000);  //id1就是timeoutID
var id2 = setInterval(f,1000); //id2就是timeoutID

clearTimeout(id1);
clearInterval(id2);
複製代碼

setTimeout()的this指向:

對於javascript中的this指向問題,以前也是困擾了我很久,哎呀,哪兒有那麼難嘛,其實一句話就是說:誰調用的就是指向誰啊!意思就是說調用的對象是誰this就是指向誰。

那這樣說來個栗子咯:

var x = 1;
var obj = {
  x: 2,
  y: function(){
    console.log(this.x);
  }
};
setTimeout(obj.y,1000);  // 1

複製代碼

why?不是說了哪一個對象調用的就是指向哪一個對象的嘛,這裏不是setTimeout函數調用了obj對象裏面的y方法嗎,那不仍是被setTimeout調用了嗎,對啊,沒錯啊,就是setTimeout調用的,可是setTimeout函數是屬於window的,知道吧,因此setTimeout的對象是window,因此一切都明瞭了。

懂了吧,那就來考考你,準備接招啦!
function Animal(login) {
  this.login = login;
  this.sayHi = function() {
    console.log(this.login);  //undefined
  }
}
var dog = new Animal('John');
setTimeout(dog.sayHi, 1000);

複製代碼

哈哈哈,答對了吧,哇👋,可是沒有獎勵😂

等到dog.sayHi執行時,它是在全局對象中執行,可是this.login取不到值。

setTimeout()之延遲時間爲0

要回答面試官問個人問題了😂。哇,血的教訓,來來來 直接一點來栗子吧:

console.log('a');
    setTimeout(function(){
    console.log('b');
    },0);
    console.log('c');
    console.log('d');
複製代碼

控制檯輸出:
a
c
d
b
我也不截圖了。 知道爲何嗎,理論上他延遲時間爲0不是應該立刻執行嗎,不是的。由於setTimeout運行機制說過,必需要等到當前腳本的同步任務和「任務隊列」中已有的事件,所有處理完之後,纔會執行setTimeout指定的任務。也就是說,setTimeout的真正做用是,在「任務隊列」的現有事件的後面再添加一個事件,規定在指定時間執行某段代碼。setTimeout添加的事件,會在下一次Event Loop執行。好吧,對事件循環不清楚的推薦看看阮一峯-avaScript 運行機制詳解

到這裏setTimeout還有什麼沒有說的呢,就是setTimeout的執行機制啊

事件循環中的setTimeout():

衆所周知,Javascript引擎(如下簡稱JS引擎)是單線程的,在某一個特定的時間內只能執行一個任務,並阻塞其餘任務的執行,也就是說這些任務是串行的。這樣的話,用戶不得不等待一個耗時的操做完成以後才能進行後面的操做,這顯然是不能容忍的,可是實際開發中咱們卻可使用異步代碼來解決。

當異步方法好比這裏的setTimeout(),或者ajax請求、DOM事件執行的時候,會交由瀏覽器內核的其餘模塊去管理。當異步的方法知足觸發條件後,該模塊就會將方法推入到一個任務隊列中,當主線程代碼執行完畢處於空閒狀態的時候,就會去檢查任務隊列,將隊列中第一個任務入棧執行,完畢後繼續檢查任務隊列,如此循環。前提條件是主線程處於空閒狀態,這就是事件循環的模型。

正經的講了一波理論,來個栗子吧:

setTimeout(function () {
    console.log("b");
},0)
console.log("a");
複製代碼

控制檯輸出:
a
b
原理,就是上面兩段話當中解釋的,執行時把setTimeout()放入任務隊列中去,主線程執行完主線程的任務以後去任務隊列裏面執行setTimeout出來執行。

同樣的道理:

setTimeout(function(){
  console.log(1111);
},0)
while (true) {};
複製代碼

這裏控制檯是永遠不會輸出東西的,由於主線程已經形成了死循環,主線程一直是不會空閒的,他不會到任務隊列裏面去執行拿setTimeout函數來執行。
推薦一篇文章,更好的理解:完全理解setTimeout()

總結:

說了這麼多,setTimeout是否是很強大,啊哈哈。可是如不能熟練掌握,不建議多用。畢竟在某些情景之下畢竟在某些情景之下,setTimeout做爲一個hack的方式而存在的。

到這裏,首先,恭喜你,應該是收穫滿滿了。其次能夠點個贊😜

相關文章
相關標籤/搜索