溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript運(yùn)行機(jī)制是怎么樣的

發(fā)布時(shí)間:2022-03-24 14:45:06 來(lái)源:億速云 閱讀:144 作者:小新 欄目:web開(kāi)發(fā)

這篇文章主要介紹了JavaScript運(yùn)行機(jī)制是怎么樣的,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

JS的運(yùn)行機(jī)制

1. js單線程

JavaScript語(yǔ)言的一大特點(diǎn)就是單線程,即同一時(shí)間只能做一件事情。

JavaScript的單線程,與它的用途有關(guān)。作為瀏覽器腳本語(yǔ)言,JavaScript的主要用途是與用戶互動(dòng),以及操作DOM。這決定了它只能是單線程,否則會(huì)帶來(lái)很復(fù)雜的同步問(wèn)題。比如,假定JavaScript同時(shí)有兩個(gè)線程,一個(gè)線程在某個(gè)DOM節(jié)點(diǎn)上添加內(nèi)容,另一個(gè)線程刪除了這個(gè)節(jié)點(diǎn),這時(shí)瀏覽器應(yīng)該以哪個(gè)線程為準(zhǔn)?

所以,為了避免復(fù)雜性,從一誕生,JavaScript就是單線程,這已經(jīng)成了這門(mén)語(yǔ)言的核心特征,將來(lái)也不會(huì)改變。

2. js事件循環(huán)

js代碼執(zhí)行過(guò)程中會(huì)有很多任務(wù),這些任務(wù)總的分成兩類(lèi):

  • 同步任務(wù)

  • 異步任務(wù)

當(dāng)我們打開(kāi)網(wǎng)站時(shí),網(wǎng)頁(yè)的渲染過(guò)程就是一大堆同步任務(wù),比如頁(yè)面骨架和頁(yè)面元素的渲染。而像加載圖片音樂(lè)之類(lèi)占用資源大耗時(shí)久的任務(wù),就是異步任務(wù)。,我們用導(dǎo)圖來(lái)說(shuō)明: JavaScript運(yùn)行機(jī)制是怎么樣的 我們解釋一下這張圖:

  • 同步和異步任務(wù)分別進(jìn)入不同的執(zhí)行"場(chǎng)所",同步的進(jìn)入主線程,異步的進(jìn)入Event Table并注冊(cè)函數(shù)。

  • 當(dāng)指定的事情完成時(shí),Event Table會(huì)將這個(gè)函數(shù)移入Event Queue

  • 主線程內(nèi)的任務(wù)執(zhí)行完畢為空,會(huì)去Event Queue讀取對(duì)應(yīng)的函數(shù),進(jìn)入主線程執(zhí)行。

  • 上述過(guò)程會(huì)不斷重復(fù),也就是常說(shuō)的Event Loop(事件循環(huán))。

那主線程執(zhí)行棧何時(shí)為空呢?js引擎存在monitoring process進(jìn)程,會(huì)持續(xù)不斷的檢查主線程執(zhí)行棧是否為空,一旦為空,就會(huì)去Event Queue那里檢查是否有等待被調(diào)用的函數(shù)。

以上就是js運(yùn)行的整體流程

需要注意的是除了同步任務(wù)和異步任務(wù),任務(wù)還可以更加細(xì)分為macrotask(宏任務(wù))和microtask(微任務(wù)),js引擎會(huì)優(yōu)先執(zhí)行微任務(wù)

微任務(wù)包括了 promise 的回調(diào)、node 中的 process.nextTick 、對(duì) Dom 變化監(jiān)聽(tīng)的 MutationObserver。

宏任務(wù)包括了 script 腳本的執(zhí)行、setTimeout ,setInterval ,setImmediate 一類(lèi)的定時(shí)事件,還有如 I/O 操作、UI 渲
染等。

面試中該如何回答呢? 下面是我個(gè)人推薦的回答:

  1. 首先js 是單線程運(yùn)行的,在代碼執(zhí)行的時(shí)候,通過(guò)將不同函數(shù)的執(zhí)行上下文壓入執(zhí)行棧中來(lái)保證代碼的有序執(zhí)行。

  2. 在執(zhí)行同步代碼的時(shí)候,如果遇到了異步事件,js 引擎并不會(huì)一直等待其返回結(jié)果,而是會(huì)將這個(gè)事件掛起,繼續(xù)執(zhí)行執(zhí)行棧中的其他任務(wù)

  3. 當(dāng)同步事件執(zhí)行完畢后,再將異步事件對(duì)應(yīng)的回調(diào)加入到與當(dāng)前執(zhí)行棧中不同的另一個(gè)任務(wù)隊(duì)列中等待執(zhí)行。

  4. 任務(wù)隊(duì)列可以分為宏任務(wù)對(duì)列和微任務(wù)對(duì)列,當(dāng)當(dāng)前執(zhí)行棧中的事件執(zhí)行完畢后,js 引擎首先會(huì)判斷微任務(wù)對(duì)列中是否有任務(wù)可以執(zhí)行,如果有就將微任務(wù)隊(duì)首的事件壓入棧中執(zhí)行。

  5. 當(dāng)微任務(wù)對(duì)列中的任務(wù)都執(zhí)行完成后再去判斷宏任務(wù)對(duì)列中的任務(wù)。

最后可以用下面一道題檢測(cè)一下收獲:

setTimeout(function() {
  console.log(1)}, 0);new Promise(function(resolve, reject) {
  console.log(2);
  resolve()}).then(function() {
  console.log(3)});process.nextTick(function () {
  console.log(4)})console.log(5)

第一輪:主程開(kāi)始執(zhí)行,遇到setTimeout,將setTimeout的回調(diào)函數(shù)丟到宏任務(wù)隊(duì)列中,在往下執(zhí)行new Promise立即執(zhí)行,輸出2,then的回調(diào)函數(shù)丟到微任務(wù)隊(duì)列中,再繼續(xù)執(zhí)行,遇到process.nextTick,同樣將回調(diào)函數(shù)扔到為任務(wù)隊(duì)列,再繼續(xù)執(zhí)行,輸出5,當(dāng)所有同步任務(wù)執(zhí)行完成后看有沒(méi)有可以執(zhí)行的微任務(wù),發(fā)現(xiàn)有then函數(shù)和nextTick兩個(gè)微任務(wù),先執(zhí)行哪個(gè)呢?process.nextTick指定的異步任務(wù)總是發(fā)生在所有異步任務(wù)之前,因此先執(zhí)行process.nextTick輸出4然后執(zhí)行then函數(shù)輸出3,第一輪執(zhí)行結(jié)束。 第二輪:從宏任務(wù)隊(duì)列開(kāi)始,發(fā)現(xiàn)setTimeout回調(diào),輸出1執(zhí)行完畢,因此結(jié)果是25431

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“JavaScript運(yùn)行機(jī)制是怎么樣的”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI