1. 程式人生 > >setTimeout(fn,0)的解釋和應用

setTimeout(fn,0)的解釋和應用

前言

關於setTimeout,我之前的文章介紹過。setTimeout我們經常用來做延遲執行,那麼setTimeout(fn,0),是不是就不延遲執行了!答案肯定是否定的。這篇文章,我詳細介紹一下setTimeout(fn,0)及其應用。

案例分析

for迴圈中有setTimeout,是我們在閉包案例中經常遇到和解決的一個問題,看一下下面這個案例

for(var i =0; i <3; i++){
    setTimeout(function(){
        console.log(i);},0);
    console.log(i);}

對於上面的這個題目中的for迴圈和setTimeout結合,我之前文章中好像有寫過,但是記不清在哪裡寫的了!這個題目的列印結果是什麼呢?

分析

對於這個題目,我們可以這麼考慮,先把for迴圈裡面的內容抽出來

   setTimeout(function(){
        console.log(i);},0);
    console.log(i);

對於這個,肯定是先執行 console.log(i),後執行setTimeout。那麼,我們把上面的for迴圈拆解開來,如下:

var i =0;
setTimeout(function(){
    console.log(i);},0);
console.log(i);
i++;
setTimeout(function(){
    console.log(i);},0);
console
.log(i); i++; setTimeout(function(){ console.log(i);},0); console.log(i); i++;

因為setTimeout是註冊事件,要等到當前指令碼的同步任務和“任務佇列”中已有的事件,全部處理完以後,才能執行。因此,上面執行結果是把所有的console都執行完畢之後才能執行setTimeout,因此,執行結果如下:

012333

for迴圈和setTimeout

這個我之前文章中好像有提及過,針對這種情況,我們將上面案例如下修改,就可以將setTimeout也可以輸出1,2,3.

我們將setTimeout裡面的匿名函式修改成自呼叫匿名函式

function(){
        console.log(i);}

修改成

(function(n){
        console.log(n);})(i)

因為setTimeout的第一個引數必須是fn,因此,我們要對這個匿名函式返回一個function

(function(n){returnfunction(){
                console.log(n);};})(i)

那麼,程式碼如下:

for(var i =0; i <3; i++){
    setTimeout((function(n){returnfunction(){
            console.log(n);};})(i),0);
    console.log(i);}

這樣執行結果就是

012012

應用

我們看下面的執行結果

console.log(1);

setTimeout(function(){
  console.log(2);},0);Promise.resolve().then(function(){
  console.log(3);}).then(function(){
  console.log(4);});

console.log(5);// 1// 5// 3// 4// 2

上面程式碼的執行結果說明,setTimeout(fn, 0)在Promise.resolve之後執行。這是因為setTimeout語句指定的是“正常任務”,即不會在當前的Event Loop(事件迴圈)執行。而Promise會將它的回撥函式,在狀態改變後的那一輪Event Loop(事件迴圈)指定為微任務。所以,3和4輸出在5之後、2之前。

setTimeout(fn, 0)的一大應用是,可以調整事件的發生順序。比如,網頁開發中,某個事件先發生在子元素,然後冒泡到父元素,即子元素的事件回撥函式,會早於父元素的事件回撥函式觸發。如果,我們先讓父元素的事件回撥函式先發生,就要用到setTimeout(fn, 0)。

案例如下:

document.getElementById("haoroomsID").onclick =function A(){
  setTimeout(function B(){
    console.log("觸發子元素事件")},0)};

document.body.onclick =function C(){
 console.log("觸發父元素事件")};

上面案例,點選haoroomsID會先觸發父級元素事件,然後再觸發子元素事件。