《JavaScript總結》js的運行機制

首先你們都知道javascript是單線程語言。javascript

什麼是單線程呢?好比咱們去車站買票,只有一個售票窗口,你們排隊買票,須要前面的人買完票,後面的人才能買票。html

那爲何javascript不能是多線程呢?java

這主要和它的用途有關。假如javascript能夠多線程,例如操做DOM元素,一個線程往DOM裏面添加內容,另外一個線程則刪除內容,那這時瀏覽器應該用哪一個線程呢?瀏覽器

 

任務隊列多線程

從上面的例子中能夠知道,單線程是有一個隊列的,而且是有順序的執行(按順序買票)。異步

咱們在考慮一個問題。假如第一個買票的人遇到一些問題,那後面的人不是得一直等着?函數

回到javascript中,咱們優秀的設計者固然能想到這個問題。因而就出現了「同步任務」和「異步任務」,簡單點來講,同步是阻塞模式,而異步是非阻塞模式。oop

 

javascript代碼執行時,會有一個主線程,主線程會將同步任務一個一個往下執行,spa

當遇到異步任務時,會將異步任務放入任務隊列。線程

當主線程把代碼執行完以後,在從任務隊列中取出一個任務放入主線程中執行。

 

console.log("1");
setTimeout(()=>{
     console.log("2");
})
console.log("3");

咱們看一下上面這段代碼的執行順序:

第一步:首先會輸出 1

第二步:當執行到setTimeout時,它會被放到任務隊列中,由於它是異步的。

第三步:輸出 3

第四步:主線程已執行完畢,主線程將setTimeout從任務隊列中取出執行,輸出 3

 

宏任務與微任務

任務隊列又分宏任務和微任務。

宏任務:總體代碼script,setTimeout,setInterval等。

微任務:Promise,process.nextTick等。

即然有分類,那它倆確定是有區別的,微任務優先於宏任務執行。

 

    setTimeout(()=>{
        console.log("定時器執行了");
    })

    new Promise((resolve)=>{
        for(var i = 0;i<100;i++){
            i==20&&resolve()
        }
    }).then(()=>{
        console.log("then函數執行了");
    })

    console.log("程序結束");

瀏覽器輸出結果以下

setTimeout和then都屬於異步,按理說應該是setTimeout先執行的呀,但爲何then先執行了?

其實上面已經解釋過了,由於Promise屬於微任務,而setTimeout屬於宏任務,因此then先執行。

 

若是還不理解,咱們看下面這個例子。

    setTimeout(()=>{//定時器1
        new Promise((resolve)=>{
            console.log("1");
            resolve();
        }).then(()=>{//then
            console.log("2");
        })

        setTimeout(()=>{//定時器1的子定時器
            console.log("3");
        })
    })

    setTimeout(()=>{//定時器2
        console.log("4");
    })

咱們來分析一下上面的代碼:

第一步:代碼中有兩個定時器,分別是「定時器1」和「定時器2」,由於它倆都屬於異步任務,因此會被加入到任務隊列中。

 

第二步:除了「定時器1」和「定時器2」(這個兩個任務都屬於宏任務),已經沒有別的任務了,此時主程序將「定時器1」從任務隊列中取出來執行。而後輸出1 ,

「定時器1」裏面還有有兩個任務,分別是微任務"then" 和 宏任務「定時器1的子定時器」,它倆都會被添加到任務隊列中,這時任務隊列中有「定時器2」、「then」、「定時器1的子定時器」。

 

第三步:主程序將「then」從任務隊列中取出並執行,輸出2  ,爲何會先取"then"呢?按代碼順序不該該是「定時器2」、「then」、「定時器1的子定時器」 ?由於"then"是微任務,因此它的優先級

高於「定時器2」、「定時器1的子定時器」,也能夠理解爲,當有微任務進入隊列時,它會放到宏任務的前面。

 

第四步:而後主程序會按順序將「定時器2」、「定時器1的子定時器」從任務隊列中取出來執行。

 

因此最後打印的結果是:1 2 4 3

 

你們有沒有發現,主程序執行完成以後,它會從任務隊列中去讀取一個任務,而後放到主程序中執行。

只要任務隊列中還有任務,主程序就會一直進行「讀取」、「執行」操做。

 

因此能夠得出如下結論:主線程從"任務隊列"中讀取事件,這個過程是循環不斷的,因此整個的這種運行機制又稱爲Event Loop(事件循環)。

 

教程參考地址:阮一峯老師的《JavaScript 運行機制詳解:再談Event Loop》

相關文章
相關標籤/搜索