国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

javascript引擎執(zhí)行的過程的理解--執(zhí)行階段

Achilles / 1989人閱讀

摘要:如果對語法分析和預(yù)編譯,還有疑問引擎執(zhí)行的過程的理解語法分析和預(yù)編譯階段。參與執(zhí)行過程的線程分別是引擎線程也稱為內(nèi)核,負(fù)責(zé)解析執(zhí)行腳本程序的主線程例如引擎。以上便是引擎執(zhí)行宏任務(wù)的整個過程。

一、概述

js引擎執(zhí)行過程主要分為三個階段,分別是語法分析,預(yù)編譯和執(zhí)行階段,上篇文章我們介紹了語法分析和預(yù)編譯階段,那么我們先做個簡單概括,如下:

1、語法分析: 分別對加載完成的代碼塊進(jìn)行語法檢驗(yàn),語法正確則進(jìn)入預(yù)編譯階段;不正確則停止該代碼塊的執(zhí)行,查找下一個代碼塊并進(jìn)行加載,加載完成再次進(jìn)入該代碼塊的語法分析階段。

2、預(yù)編譯:通過語法分析階段后,進(jìn)入預(yù)編譯階段,則創(chuàng)建變量對象(創(chuàng)建arguments對象(函數(shù)運(yùn)行環(huán)境下),函數(shù)聲明提前解析,變量聲明提升),確定作用域鏈以及this指向。

如果對語法分析和預(yù)編譯,還有疑問:javascript引擎執(zhí)行的過程的理解--語法分析和預(yù)編譯階段。

同步更新sau交流學(xué)習(xí)社區(qū)(nodeJSBlog):javascript引擎執(zhí)行的過程的理解--執(zhí)行階段(www.mwcxs.top/page/564.ht…

本文主要分析js引擎執(zhí)行的第三個階段–執(zhí)行階段,在分析之前我們先思考以下兩個問題:

1、js是單線程的,為了避免代碼解析阻塞使用了異步執(zhí)行,那么它的異步執(zhí)行機(jī)制是怎么樣的?

答:通過事件循環(huán)(Event Loop),理解了事件循環(huán)的原理就理解了js的異步執(zhí)行機(jī)制,本文主要介紹。

2、js是單線程的,那么是否代表參與js執(zhí)行過程的線程就只有一個?

答:不是的,會有四個線程參與該過程,但是永遠(yuǎn)只有JS引擎線程在執(zhí)行JS腳本程序,其他的三個線程只協(xié)助,不參與代碼解析與執(zhí)行。參與js執(zhí)行過程的線程分別是:

(1)JS引擎線程: 也稱為JS內(nèi)核,負(fù)責(zé)解析執(zhí)行Javascript腳本程序的主線程(例如V8引擎)。

(2)事件觸發(fā)線程: 歸屬于瀏覽器內(nèi)核進(jìn)程,不受JS引擎線程控制。主要用于控制事件(例如鼠標(biāo),鍵盤等事件),當(dāng)該事件被觸發(fā)時候,事件觸發(fā)線程就會把該事件的處理函數(shù)推進(jìn)事件隊(duì)列,等待JS引擎線程執(zhí)行。

(3)定時器觸發(fā)線程:主要控制計(jì)時器setInterval和延時器setTimeout,用于定時器的計(jì)時,計(jì)時完畢,滿足定時器的觸發(fā)條件,則將定時器的處理函數(shù)推進(jìn)事件隊(duì)列中,等待JS引擎線程執(zhí)行。

注:W3C在HTML標(biāo)準(zhǔn)中規(guī)定setTimeout低于4ms的時間間隔算為4ms。

(4)HTTP異步請求線程:通過XMLHttpRequest連接后,通過瀏覽器新開的一個線程,監(jiān)控readyState狀態(tài)變更時,如果設(shè)置了該狀態(tài)的回調(diào)函數(shù),則將該狀態(tài)的處理函數(shù)推進(jìn)事件隊(duì)列中,等待JS引擎線程執(zhí)行。

注:瀏覽器對同一域名請求的并發(fā)連接數(shù)是有限制的,Chrome和Firefox限制數(shù)為6個,ie8則為10個。

總結(jié):永遠(yuǎn)只有JS引擎線程在執(zhí)行JS腳本程序,其他三個線程只負(fù)責(zé)將滿足觸發(fā)條件的處理函數(shù)推進(jìn)事件隊(duì)列,等待JS引擎線程執(zhí)行。

二、執(zhí)行階段

先分析一個典型的例子(來自Tasks, microtasks, queues and schedules,建議英文基礎(chǔ)好的閱讀,非常不錯的文章):

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");

直接劃分例子的代碼結(jié)構(gòu),簡單描述分析執(zhí)行過程;

暫不解釋該過程中的概念和原理,概念和原理將會在下面具體講解如下:

1、宏任務(wù)(macro-task)

宏任務(wù)(macro-task),宏任務(wù)又按執(zhí)行順序分為同步任務(wù)和異步任務(wù)

(1)同步任務(wù)

console.log("script start");
console.log("script end");

(2)異步任務(wù)

setTimeout(function() {
  console.log("setTimeout");
}, 0);
2、微任務(wù)(micro-task)
Promise.resolve().then(function() {
  console.log("promise1");
}).then(function() {
  console.log("promise2");
});

在JS引擎執(zhí)行過程中,進(jìn)入執(zhí)行階段后,代碼的執(zhí)行順序如下:

宏任務(wù)(同步任務(wù)) --> 微任務(wù) --> 宏任務(wù)(異步任務(wù))

輸出結(jié)果:

script start
script end
promise1
promise2
setTimeout

進(jìn)入ES6或Node環(huán)境中,JS的任務(wù)分為兩種,分別是宏任務(wù)(macro-task)和微任務(wù)(micro-task),在最新的ECMAScript中,微任務(wù)稱為jobs,宏任務(wù)稱為task,他們的執(zhí)行順序如上??赡芎芏嗳藢ι厦娴姆治霾⒉焕斫?,那么我們接下來繼續(xù)對上面例子進(jìn)行詳細(xì)分析。

2.1宏任務(wù)

宏任務(wù)(macro-task)可分為同步任務(wù)和異步任務(wù):

1、同步任務(wù)指的是在JS引擎主線程上按順序執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢后,才能執(zhí)行后一個任務(wù),形成一個執(zhí)行棧(函數(shù)調(diào)用棧)。

2、異步任務(wù)指的是不直接進(jìn)入JS引擎主線程,而是滿足觸發(fā)條件時,相關(guān)的線程將該異步任務(wù)推進(jìn)任務(wù)隊(duì)列(task queue),等待JS引擎主線程上的任務(wù)執(zhí)行完畢,空閑時讀取執(zhí)行的任務(wù),例如異步Ajax,DOM事件,setTimeout等。

理解宏任務(wù)中同步任務(wù)和異步任務(wù)的執(zhí)行順序,那么就相當(dāng)于理解了JS異步執(zhí)行機(jī)制–事件循環(huán)(Event Loop)。

2.1.1事件循環(huán)

事件循環(huán)可以理解成由三部分組成,分別是:

1、主線程執(zhí)行棧

2、異步任務(wù)等待觸發(fā)

3、任務(wù)隊(duì)列

任務(wù)隊(duì)列(task queue)就是以隊(duì)列的數(shù)據(jù)結(jié)構(gòu)對事件任務(wù)進(jìn)行管理,特點(diǎn)是先進(jìn)先出,后進(jìn)后出。

這里直接引用一張著名的圖片(參考自Philip Roberts的演講《Help, I’m stuck in an event-loop》),幫助我們理解,如下:

在JS引擎主線程執(zhí)行過程中:

1、首先執(zhí)行宏任務(wù)的同步任務(wù),在主線程上形成一個執(zhí)行棧,可理解為函數(shù)調(diào)用棧。

2、當(dāng)執(zhí)行棧中的函數(shù)調(diào)用到一些異步執(zhí)行的API(例如異步Ajax,DOM事件,setTimeout等API),則會開啟對應(yīng)的線程(Http異步請求線程,事件觸發(fā)線程和定時器觸發(fā)線程)進(jìn)行監(jiān)控和控制。

3、當(dāng)異步任務(wù)的事件滿足觸發(fā)條件時,對應(yīng)的線程則會把該事件的處理函數(shù)推進(jìn)任務(wù)隊(duì)列(task queue)中,等待主線程讀取執(zhí)行。

4、當(dāng)JS引擎主線程上的任務(wù)執(zhí)行完畢,則會讀取任務(wù)隊(duì)列中的事件,將任務(wù)隊(duì)列中的事件任務(wù)推進(jìn)主線程中,按任務(wù)隊(duì)列順序執(zhí)行

5、當(dāng)JS引擎主線程上的任務(wù)執(zhí)行完畢后,則會再次讀取任務(wù)隊(duì)列中的事件任務(wù),如此循環(huán),這就是事件循環(huán)(Event Loop)的過程。

如果還是不能理解,那么我們再次拿上面的例子進(jìn)行詳細(xì)分析,該例子中宏任務(wù)的代碼部分是:

console.log("script start");

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

console.log("script end");

代碼執(zhí)行過程如下:

1、JS引擎主線程按代碼順序執(zhí)行,當(dāng)執(zhí)行到console.log("script start");,JS引擎主線程認(rèn)為該任務(wù)是同步任務(wù),所以立刻執(zhí)行輸出script start,然后繼續(xù)向下執(zhí)行。

2、JS引擎主線程執(zhí)行到setTimeout(function() { console.log("setTimeout"); }, 0);,JS引擎主線程認(rèn)為setTimeout是異步任務(wù)API,則向?yàn)g覽器內(nèi)核進(jìn)程申請開啟定時器線程進(jìn)行計(jì)時和控制該setTimeout任務(wù)。由于W3C在HTML標(biāo)準(zhǔn)中規(guī)定setTimeout低于4ms的時間間隔算為4ms,那么當(dāng)計(jì)時到4ms時,定時器線程就把該回調(diào)處理函數(shù)推進(jìn)任務(wù)隊(duì)列中等待主線程執(zhí)行,然后JS引擎主線程繼續(xù)向下執(zhí)行。

3、JS引擎主線程執(zhí)行到console.log("script end");,JS引擎主線程認(rèn)為該任務(wù)是同步任務(wù),所以立刻執(zhí)行輸出script end。

4、JS引擎主線程上的任務(wù)執(zhí)行完畢(輸出script start和script end)后,主線程空閑,則開始讀取任務(wù)隊(duì)列中的事件任務(wù),將該任務(wù)隊(duì)里的事件任務(wù)推進(jìn)主線程中,按任務(wù)隊(duì)列順序執(zhí)行,最終輸出setTimeout,所以輸出的結(jié)果順序?yàn)閟cript start script end setTimeout。

以上便是JS引擎執(zhí)行宏任務(wù)的整個過程。

理解該過程后,我們做一些拓展性的思考:

我們都知道setTimeout和setInterval是異步任務(wù)的定時器,需要添加到任務(wù)隊(duì)列等待主線程執(zhí)行,那么使用setTimeout模擬實(shí)現(xiàn)setInterval,會有區(qū)別嗎?

答案是有區(qū)別的,我們不妨思考一下:

1、setTimeout實(shí)現(xiàn)setInterval只能通過遞歸調(diào)用。

2、setTimeout是在到了指定時間的時候就把事件推到任務(wù)隊(duì)列中,只有當(dāng)在任務(wù)隊(duì)列中的setTimeout事件被主線程執(zhí)行后,才會繼續(xù)再次在到了指定時間的時候把事件推到任務(wù)隊(duì)列,那么setTimeout的事件執(zhí)行肯定比指定的時間要久,具體相差多少跟代碼執(zhí)行時間有關(guān)。

3、setInterval則是每次都精確的隔一段時間就向任務(wù)隊(duì)列推入一個事件,無論上一個setInterval事件是否已經(jīng)執(zhí)行,所以有可能存在setInterval的事件任務(wù)累積,導(dǎo)致setInterval的代碼重復(fù)連續(xù)執(zhí)行多次,影響頁面性能。

綜合以上的分析,使用setTimeout實(shí)現(xiàn)計(jì)時功能是比setInterval性能更好的。當(dāng)然如果不需要兼容低版本的IE瀏覽器,使用requestAnimationFrame是更好的選擇。

我們繼續(xù)再做進(jìn)一步的思考,如下:

高頻率觸發(fā)的事件(例如滾動事件)觸發(fā)頻率過高會影響頁面性能,甚至造成頁面卡頓,我們是否可以利用計(jì)時器的原理進(jìn)行優(yōu)化呢?

是可以的,我們可以利用setTimeout實(shí)現(xiàn)計(jì)時器的原理,對高頻觸發(fā)的事件進(jìn)行優(yōu)化,實(shí)現(xiàn)點(diǎn)在于將多個觸發(fā)事件合并成一個,這就是防抖和節(jié)流,本文先不做具體講解,大家可以自行研究,有機(jī)會我再另開文章分析。

2.2微任務(wù)

微任務(wù)是在es6和node環(huán)境中出現(xiàn)的一個任務(wù)類型,如果不考慮es6和node環(huán)境的話,我們只需要理解宏任務(wù)事件循環(huán)的執(zhí)行過程就已經(jīng)足夠了,但是到了es6和node環(huán)境,我們就需要理解微任務(wù)的執(zhí)行順序了。微任務(wù)(micro-task)的API主要有:Promise, process.nextTick

這里我們直接引用一張流程圖幫助我們理解,如下:

在宏任務(wù)中執(zhí)行的任務(wù)有兩種,分別是同步任務(wù)和異步任務(wù),因?yàn)楫惒饺蝿?wù)會在滿足觸發(fā)條件時才會推進(jìn)任務(wù)隊(duì)列(task queue),然后等待主線程上的任務(wù)執(zhí)行完畢,再讀取任務(wù)隊(duì)列中的任務(wù)事件,最后推進(jìn)主線程執(zhí)行,所以這里將異步任務(wù)即任務(wù)隊(duì)列看作是新的宏任務(wù)。執(zhí)行的過程如上圖所示:

1、執(zhí)行宏任務(wù)中同步任務(wù),執(zhí)行結(jié)束。

2、檢查是否存在可執(zhí)行的微任務(wù),有的話執(zhí)行所有微任務(wù),然后讀取任務(wù)隊(duì)列的任務(wù)事件,推進(jìn)主線程形成新的宏任務(wù);沒有的話則讀取任務(wù)隊(duì)列的任務(wù)事件,推進(jìn)主線程形成新的宏任務(wù)。

3、執(zhí)行新宏任務(wù)的事件任務(wù),再檢查是否存在可執(zhí)行的微任務(wù),如此不斷的重復(fù)循環(huán)。

這就是加入微任務(wù)后的詳細(xì)事件循環(huán),如果還沒有理解,那么們對一開始的例子做一個全面的分析,如下:

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");

執(zhí)行過程如下:

1、代碼塊通過語法分析和預(yù)編譯后,進(jìn)入執(zhí)行階段,當(dāng)JS引擎主線程執(zhí)行到console.log("script start");,JS引擎主線程認(rèn)為該任務(wù)是同步任務(wù),所以立刻執(zhí)行輸出script start,然后繼續(xù)向下執(zhí)行。

2、JS引擎主線程執(zhí)行到setTimeout(function() { console.log("setTimeout"); }, 0);,JS引擎主線程認(rèn)為setTimeout是異步任務(wù)API,則向?yàn)g覽器內(nèi)核進(jìn)程申請開啟定時器線程進(jìn)行計(jì)時和控制該setTimeout任務(wù)。由于W3C在HTML標(biāo)準(zhǔn)中規(guī)定setTimeout低于4ms的時間間隔算為4ms,那么當(dāng)計(jì)時到4ms時,定時器線程就把該回調(diào)處理函數(shù)推進(jìn)任務(wù)隊(duì)列中等待主線程執(zhí)行,然后JS引擎主線程繼續(xù)向下執(zhí)行。

3、JS引擎主線程執(zhí)行到Promise.resolve().then(function() { console.log("promise1"); }).then(function() { console.log("promise2"); });,JS引擎主線程認(rèn)為Promise是一個微任務(wù),這把該任務(wù)劃分為微任務(wù),等待執(zhí)行。

4、JS引擎主線程執(zhí)行到console.log("script end");,JS引擎主線程認(rèn)為該任務(wù)是同步任務(wù),所以立刻執(zhí)行輸出script end。

5、主線程上的宏任務(wù)執(zhí)行完畢,則開始檢測是否存在可執(zhí)行的微任務(wù),檢測到一個Promise微任務(wù),那么立刻執(zhí)行,輸出promise1和promise2

6、微任務(wù)執(zhí)行完畢,主線程開始讀取任務(wù)隊(duì)列中的事件任務(wù)setTimeout,推入主線程形成新宏任務(wù),然后在主線程中執(zhí)行,輸出setTimeout

最后輸出結(jié)果:

script start
script end
promise1
promise2
setTimeout
三、總結(jié)

以上便是JS引擎執(zhí)行的全部過程,JS引擎的執(zhí)行過程其實(shí)并不復(fù)雜,只要多思考多研究就可以理解,理解該過程后可以在一定程度上提高對JS的認(rèn)識。

四、參考文獻(xiàn)

Tasks, microtasks, queues and schedules

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/7028.html

相關(guān)文章

  • javascript引擎執(zhí)行過程理解--執(zhí)行階段

    摘要:如果對語法分析和預(yù)編譯,還有疑問引擎執(zhí)行的過程的理解語法分析和預(yù)編譯階段。參與執(zhí)行過程的線程分別是引擎線程也稱為內(nèi)核,負(fù)責(zé)解析執(zhí)行腳本程序的主線程例如引擎。以上便是引擎執(zhí)行宏任務(wù)的整個過程。 一、概述 js引擎執(zhí)行過程主要分為三個階段,分別是語法分析,預(yù)編譯和執(zhí)行階段,上篇文章我們介紹了語法分析和預(yù)編譯階段,那么我們先做個簡單概括,如下: 1、語法分析: 分別對加載完成的代碼塊進(jìn)行語法...

    SnaiLiu 評論0 收藏0
  • javascript系列--javascript引擎執(zhí)行過程理解--語法分析和預(yù)編譯階段

    摘要:所以覺得把這個執(zhí)行的詳細(xì)過程整理一下,幫助更好的理解。類似的語法報(bào)錯的如下圖所示三預(yù)編譯階段代碼塊通過語法分析階段之后,語法都正確的下回進(jìn)入預(yù)編譯階段。另開出新文章詳細(xì)分析,主要介紹執(zhí)行階段中的同步任務(wù)執(zhí)行和異步任務(wù)執(zhí)行機(jī)制事件循環(huán)。 一、概述 js是一種非常靈活的語言,理解js引擎的執(zhí)行過程對于我們學(xué)習(xí)js是非常有必要的??戳撕芏噙@方便文章,大多數(shù)是講的是事件循環(huán)(event loo...

    malakashi 評論0 收藏0
  • javascript引擎執(zhí)行過程理解--語法分析和預(yù)編譯階段

    摘要:所以覺得把這個執(zhí)行的詳細(xì)過程整理一下,幫助更好的理解。類似的語法報(bào)錯的如下圖所示三預(yù)編譯階段代碼塊通過語法分析階段之后,語法都正確的下回進(jìn)入預(yù)編譯階段。另開出新文章詳細(xì)分析,主要介紹執(zhí)行階段中的同步任務(wù)執(zhí)行和異步任務(wù)執(zhí)行機(jī)制事件循環(huán)。 一、概述 js是一種非常靈活的語言,理解js引擎的執(zhí)行過程對于我們學(xué)習(xí)js是非常有必要的。看了很多這方便文章,大多數(shù)是講的是事件循環(huán)(event loo...

    molyzzx 評論0 收藏0
  • 深入理解Javascript執(zhí)行環(huán)境(Execution Context)和執(zhí)行棧(Execut

    摘要:引擎會執(zhí)行其執(zhí)行環(huán)境位于堆棧頂部的函數(shù)。當(dāng)函數(shù)執(zhí)行完畢時,當(dāng)前執(zhí)行棧會從堆棧中彈出去,并且控件將會到達(dá)其在當(dāng)前堆棧下面的那個執(zhí)行環(huán)境中。當(dāng)完成以后,它的執(zhí)行環(huán)境會會從堆棧中移出,并且控件會到達(dá)全局執(zhí)行環(huán)境。 如果你想成為一個Javascript開發(fā)者,那么你一定要知道Javascript程序的內(nèi)部運(yùn)行原理。理解執(zhí)行環(huán)境和執(zhí)行棧是非常重要的,其有助于理解其他Javascript的概念,比...

    whidy 評論0 收藏0
  • 理解Javascript執(zhí)行上下文(Execution Context)

    摘要:瀏覽器總是運(yùn)行位于作用域鏈頂部的當(dāng)前執(zhí)行上下文。不同執(zhí)行上下文之間的變量命名沖突通過攀爬作用域鏈解決,從局部直到全局。它將攀爬作用域鏈檢查每一個執(zhí)行上下文的變量對象,尋找和變量名稱匹配的值。 1>什么是執(zhí)行上下文 Javascript中代碼的運(yùn)行環(huán)境分為以下三種:全局級別的代碼 - 這個是默認(rèn)的代碼運(yùn)行環(huán)境,一旦代碼被載入,引擎最先進(jìn)入的就是這個環(huán)境。函數(shù)級別的代碼 - 當(dāng)執(zhí)行一個函數(shù)...

    Miracle 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<