setTimeout與setInterval

前言:關於最近面試遇到的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

相關文章
相關標籤/搜索