簡單理解瀏覽器端的js執(zhí)行機制Event-Loop

先觀為敬

//執(zhí)行以下JavaScript代碼,分析代碼執(zhí)行順序
console.log('javascript1')

setTimeout(() => {
    console.log('setTimeout1');
    Promise.resolve().then(() => {
        console.log('promise1');
    })
}, 0);

setTimeout(() => {
    console.log('setTimeout2');
    Promise.resolve().then(() => {
        console.log('promise3');
    })

    setTimeout(() => {
        console.log('setTimeout3');
    }, 0)
}, 0)

Promise.resolve()
    .then(() => {
        console.log('promise4');
    }).then(() => {
        console.log('promise2');
    })
console.log('javascript2');

講真的,一開始我是懵逼的,反正正確的打印順序肯定不是從上到下執(zhí)行的。

js瀏覽器的執(zhí)行機制——Event-Loop

這里為什么會強調(diào)說是瀏覽器,我們都知道,在node平臺的JavaScript執(zhí)行機制和瀏覽器端的執(zhí)行是有區(qū)別的,至于何種區(qū)別,不在本文的討論之中

我們知道js語言是單線程的,這是js語言設(shè)計的初衷。起初,作為一個為web開發(fā)的語言,如果設(shè)計為多線程的,那么就會存在一個矛盾。比如:線程A對一個DOM結(jié)構(gòu)刪除了,線程B正在對這個DOM修改,那么瀏覽器是不是就很蛋疼了。但是在瀏覽器執(zhí)行時,又不能按照順序執(zhí)行,如果一個任務(wù)耗時過長,那么后一個任務(wù)也必須等著。那么問題來了,假如我們想打開一個網(wǎng)頁,但是該網(wǎng)頁中包含的大量圖片而且加載很慢,難道我們的網(wǎng)頁要一直卡著直到圖片完全顯示出來?可是問題總歸是要解決的,于是就誕生了:

  • 同步執(zhí)行
  • 異步執(zhí)行

下面介紹兩個例子:

//同步執(zhí)行
console.log('step1')
console.log('step2')
console.log('step3')
/*
*打印順序為
*  step1
*  step2
*  step3
*/
//異步執(zhí)行
console.log('step1')
setTimeout(function(){
   console.log('step2')
},0)
console.log('step3')
/*
*打印順序為
*  step1
*  step3
*  step2
*/

JavaScript執(zhí)行機制Event-Loop如下圖所示

image.png

我們嘗試通過JavaScript執(zhí)行機制去分析代碼執(zhí)行順序。首先先介紹兩個概念

  • 宏任務(wù):包括整體代碼script,setTimeout,setInterval,setImmediate
  • 微任務(wù):Promise,process.nextTick

分析上面的異步例子
console.log('step1')作為第一級宏任務(wù),需要立即執(zhí)行
setTimeout(function(){ console.log('step2') },0)作為第二級宏任務(wù),需要等到第一級宏任務(wù)執(zhí)行完成后,再執(zhí)行
console.log('step3')作為第一級宏任務(wù),需要立即執(zhí)行

再嘗試分析一串簡單的代碼

setTimeout(function(){
     console.log('step1')
 });
 
 new Promise(function(resolve){
     console.log('step2');
     for(var i = 0; i < 10000; i++){
         i == 99 && resolve();
     }
 }).then(function(){
     console.log('step3')
 });
 
 console.log('step4');

1.setTimeout(function(){ console.log('step1') });作為異步任務(wù)放在宏任務(wù)隊列中,等待執(zhí)行
2.new Promise立即執(zhí)行,打印step2,then鏈?zhǔn)俏⑷蝿?wù)放入微任務(wù)隊列中等待本次宏任務(wù)執(zhí)行完成后執(zhí)行
3.console.log('step4')立即執(zhí)行,打印step4
4.本次宏任務(wù)執(zhí)行完成,查看微任務(wù)隊列中發(fā)現(xiàn)還有promise的then鏈沒有執(zhí)行,立即執(zhí)行then鏈中的console.log('step3')
5.本輪任務(wù)完成后,查看宏任務(wù)的隊列里還有一個定時器,執(zhí)行定時器的console.log('step1')
所以打印結(jié)果為step2-step4-step3-step1

當(dāng)理解了js瀏覽器的執(zhí)行機制后,再來看文章開始的例子就可以很清晰的得出代碼打印的結(jié)果

javascript1
javascript2
promise4
promise2
setTimeout1
promise1
setTimeout2
promise3
setTimeout3

setTimeout的執(zhí)行

setTimeout(function(){
     console.log('setTimeout')
 },1000);

通常setTimeout定時器是指在xx秒后執(zhí)行,其實在js的運行機制里,是在xx秒后將setTimeout里的回調(diào)函數(shù)推入到event queue隊列中,但是并沒有立即執(zhí)行,而是等到j(luò)s主線程空閑之后再執(zhí)行,比如上面的代碼中,一秒鐘后執(zhí)行console.log('setTimeout'),如果主線程的任務(wù)在1秒鐘內(nèi)沒有執(zhí)行完成,那么console.log('setTimeout')也不會在一秒后執(zhí)行。所以說setTimeout在一秒鐘后并且主線程空閑兩個條件同時滿足才會執(zhí)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容