您好,登錄后才能下訂單哦!
這篇文章主要介紹了JavaScript運(yùn)行機(jī)制是怎么樣的,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
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ì)改變。
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ō)明: 我們解釋一下這張圖:
同步和異步任務(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è)人推薦的回答:
首先js 是單線程運(yùn)行的,在代碼執(zhí)行的時(shí)候,通過(guò)將不同函數(shù)的執(zhí)行上下文壓入執(zhí)行棧中來(lái)保證代碼的有序執(zhí)行。
在執(zhí)行同步代碼的時(shí)候,如果遇到了異步事件,js 引擎并不會(huì)一直等待其返回結(jié)果,而是會(huì)將這個(gè)事件掛起,繼續(xù)執(zhí)行執(zhí)行棧中的其他任務(wù)
當(dāng)同步事件執(zhí)行完畢后,再將異步事件對(duì)應(yīng)的回調(diào)加入到與當(dāng)前執(zhí)行棧中不同的另一個(gè)任務(wù)隊(duì)列中等待執(zhí)行。
任務(wù)隊(duì)列可以分為宏任務(wù)對(duì)列和微任務(wù)對(duì)列,當(dāng)當(dāng)前執(zhí)行棧中的事件執(zhí)行完畢后,js 引擎首先會(huì)判斷微任務(wù)對(duì)列中是否有任務(wù)可以執(zhí)行,如果有就將微任務(wù)隊(duì)首的事件壓入棧中執(zhí)行。
當(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í)!
免責(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)容。