Javascript運行機制理解總結(jié)

首先,我想說一下Javascript的裝載和執(zhí)行。
通常來說,瀏覽器對于Javascript的運行有兩大特性:
1)載入后馬上執(zhí)行,
2)執(zhí)行時會阻塞頁面后續(xù)的內(nèi)容(包括頁面的渲染、其它資源的下載)**。于是,如果有多個js文件被引入,那么對于瀏覽器來說,這些js文件被被串行地載入,并依次執(zhí)行。

因為javascript可能會來操作HTML文檔的DOM樹,所以,瀏覽器一般都不會像并行下載css文件并行下載js文件,因為這是js文件的特殊性造成的。

所以,如果你的javascript想操作后面的DOM元素,基本上來說,瀏覽器都會報錯說對象找不到。因為Javascript執(zhí)行時,后面的HTML被阻塞住了,DOM樹時還沒有后面的DOM結(jié)點。所以程序也就報錯了。

有沒有辦法實現(xiàn)只加載不立即執(zhí)行,后續(xù)按需執(zhí)行呢?

http://www.linjunlong.com/p/1156.html 這里有一種方案。

下面說說具體執(zhí)行:

  • 棧和隊列


    image.png

在上圖中,調(diào)用棧中遇到DOM操作、ajax請求以及setTimeout等WebAPIs的時候就會交給瀏覽器內(nèi)核的其他模塊進行處理,webkit內(nèi)核在Javasctipt執(zhí)行引擎之外,有一個重要的模塊是webcore模塊。對于圖中WebAPIs提到的三種API,webcore分別提供了DOM Binding、network、timer模塊來處理底層實現(xiàn)。等到這些模塊處理完這些操作的時候?qū)⒒卣{(diào)函數(shù)放入任務(wù)隊列中,之后等棧中的task執(zhí)行完之后再去執(zhí)行任務(wù)隊列之中的回調(diào)函數(shù)

可以看出:
所有的代碼都要通過函數(shù)調(diào)用棧中調(diào)用執(zhí)行。
當(dāng)遇到前文中提到的APIs的時候,會交給瀏覽器內(nèi)核的其他模塊進行處理。
任務(wù)隊列中存放的是回調(diào)函數(shù)。
等到調(diào)用棧中的task執(zhí)行完之后再回去執(zhí)行任務(wù)隊列之中的task。

  • 整個事件循環(huán)機制包含兩種事件隊列
(function test() {
 /*開始執(zhí)行本次macro-task*/
    setTimeout(function() {console.log(4)}, 0);----作為一個macro-task,將其回調(diào)函數(shù)放入自己的隊列之中。
    new Promise(function executor(resolve) {
        console.log(1);---- 立即執(zhí)行
        for( var i=0 ; i<10000 ; i++ ) {
            i == 9999 && resolve();
        }
        console.log(2);---- 立即執(zhí)行
    }).then(function() {
        console.log(5);---micro task queue
    });
    console.log(3);---- 立即執(zhí)行
})()

macro-task包括:script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering。

micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver

事件循環(huán)的順序是從script開始第一次循環(huán),隨后全局上下文進入函數(shù)調(diào)用棧,碰到macro-task就將其交給處理它的模塊處理完之后將回調(diào)函數(shù)放進macro-task的隊列之中,碰到micro-task也是將其回調(diào)函數(shù)放進micro-task的隊列之中。直到函數(shù)調(diào)用棧清空只剩全局執(zhí)行上下文,然后開始執(zhí)行所有的micro-task。當(dāng)所有可執(zhí)行的micro-task執(zhí)行完畢之后。循環(huán)再次執(zhí)行macro-task中的一個任務(wù)隊列,執(zhí)行完之后再執(zhí)行所有的micro-task,就這樣一直循環(huán)。

總結(jié)

  • 不同的任務(wù)會放進不同的任務(wù)隊列之中。

  • 先執(zhí)行macro-task,等到函數(shù)調(diào)用棧清空之后再執(zhí)行所有在隊列之中的micro-task。

  • 等到所有micro-task執(zhí)行完之后再從macro-task中的一個任務(wù)隊列開始執(zhí)行,就這樣一直循環(huán)。

  • 當(dāng)有多個macro-task(micro-task)隊列時,事件循環(huán)的順序是按上文macro-task(micro-task)的分類中書寫的順序執(zhí)行的。

參考:
https://zhuanlan.zhihu.com/p/26229293

最后編輯于
?著作權(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ù)。

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