爲了解釋上面的那句話,來個簡單的小例子: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
你們都知道setInterval()和setTimeout()能夠接收兩個參數,第一個參數是須要回調的函數,必須傳入的參數,第二個參數是時間間隔,毫秒數,能夠省略。但其實他能夠接收更多的參數,那麼這些參數是幹什麼用的呢?從第三個參數開始,依次用來表示傳入回調函數的參數。瀏覽器
例子:bash
setTimeout(function(a,b){
console.log(0+a+b);//這裏打印的是:7
},1000,3,4);
複製代碼
若是想向回調函數傳參,能夠用bind()。
eg:異步
setTimeout( function(a,b){}.bind(3,4), 1000 );
複製代碼
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);
複製代碼
對於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取不到值。
要回答面試官問個人問題了😂。哇,血的教訓,來來來 直接一點來栗子吧:
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 運行機制詳解
衆所周知,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的方式而存在的。
到這裏,首先,恭喜你,應該是收穫滿滿了。其次能夠點個贊😜