前言:關於最近面試遇到的setTimeout與setInterval相關面試題,網上搜索相關資料,進行學習總結。javascript
一、setTimeout與setInterval的區別?
java
setTimeout()方法用來指定某個函數或字符串在指定的毫秒數以後執行。它返回一個整數,表示定時器的編號,這個值能夠傳遞給clearTimeout()用於取消這個函數的執行。面試
setInterval的用法與setTimeout徹底一致,區別僅僅在於setInterval指定某個任務每隔一段時間就執行一次,也就是無限次的定時執行。promise
setTimeout和setInterval函數,都返回一個表示計數器編號的整數值,將該整數傳入clearTimeout和clearInterval函數,就能夠取消對應的定時器。異步
二、看代碼,寫結果
函數
for (var i = 0; i < 5; i++) { setTimeout(function (){ console.log(i); },1000); }
結果:5,5,5,5,5學習
setTimeout是異步執行的,1000毫秒後向任務隊列裏添加一個任務,只有主線上的所有執行完纔會執行任務隊列裏的任務,因此當主線程for循環執行完以後i的值爲5,這個時候再去任務隊列中執行任務,i所有爲5;每次for循環的時候setTimeout都會執行,可是裏面的function不會執行,所以放了5次,1000毫秒後所有執行完任務隊列中的函數,因此輸出五個5.spa
同時,i是var定義的,不屬於for循環體,屬於全局global。等for循環結束,i已經等於5了,這個時候執行回調函數,裏面console.log(i)的i向上找做用域,只能找到全局下的i,即5.因此輸出都是5.線程
三、如何解決上述問題,變成0,1,2,3,4code
a、當即執行函數
這樣console.log(i)中的i就保存在每一次循環生成的當即執行函數中對的做用域裏了。
for (var i = 0; i < 5; i++) { (function(i){ //馬上執行函數 setTimeout(function (){ console.log(i); },1000); })(i); }
b、let做爲代碼塊做用域,因此每一次 for 循環,console.log(i); 都引用到 for 代碼塊做用域下的i,由於這樣被引用,因此 for 循環結束後,這些做用域在 setTimeout 未執行前都不會被釋放。
for (let i = 0; i < 5; i++) { //let 代替 var setTimeout(function (){ console.log(i); },1000); }
四、setTimeout的做用是將代碼推遲到指定時間執行,若是指定時間爲0,即setTimeout(f,0),那麼會馬上執行嗎?
不會。必須等當前腳本的同步任務和隊列任務中全部事件執行完,纔會執行setTimeout指定任務,將第二參數設置爲0,目的是以前全部任務執行完後就當即執行,儘量早得執行指定任務
五、看代碼,寫結果
console.log("script start"); setTimeout(function(){ console.log("setTimeout"); },0); Promise.resolve().then(function(){ console.log("promise1"); }).then(function(){ console.log("promise2"); }); console.log("script end");
結果:
script start
script end
promise1
promise2
setTimeout
setTimeout和Promise調用都是異步任務,都是經過任務隊列進行管理調度。分爲宏任務隊列和微任務隊列,能夠看出Promise比setTimeout()先執行。由於Promise定義以後便會當即執行,其後的.then()是異步裏面的微任務。而setTimeout()是異步的宏任務。
從script(總體代碼)開始第一次循環,全局上下文進入函數調用棧(棧底),若是有可執行代碼就進行正常的入棧出棧,若是有上面提到的setTimeout和Promise,就將任務分發到各自隊列,直到調用棧清空(只剩全局),而後執行全部的微任務隊列(Promise隊列),這就是第一次循環。當全部可執行的微任務執行完畢以後,循環再次從宏任務(setTimeout隊列)開始執行入棧出棧任務分發等,執行完畢,而後再執行全部的微任務,第二次循環結束。。。這樣一直循環下去,直到再也沒有可執行的任務。這就是JS的循環機制。
console.log('打印'+1); setTimeout(function(){ console.log('打印'+2); }) new Promise(function(resolve,reject){ console.log('打印'+3); }).then( console.log('打印'+4));; console.log('打印'+10); new Promise(function(resolve,reject){ setTimeout(function () { console.log('打印'+5); }); }).then( console.log('打印'+6)); setTimeout(function(){ new Promise(function(resolve,reject){ console.log('打印'+7); }); })
打印1
打印3
打印4
打印10
打印6
打印2
打印5
打印7
console.log('打印'+1); setTimeout(function(){ console.log('打印'+2); }) new Promise(function(resolve){ console.log('打印'+3); resolve(); }).then(function(){ console.log(4); } ); console.log('打印'+10); new Promise(function(resolve){ setTimeout(function () { console.log('打印'+5); }); resolve(); }).then(function(){ console.log('打印'+6)}); setTimeout(function(){ new Promise(function(resolve){ console.log('打印'+7); }); })
打印1打印3打印10 4打印6打印2打印5打印7