摘要:即使現(xiàn)在支持,由于沒(méi)有多線程的機(jī)制,和執(zhí)行線程只能通過(guò)來(lái)通信,而且由于沒(méi)有鎖,無(wú)法訪問(wèn)和對(duì)象。的單線程是指一個(gè)瀏覽器進(jìn)程中只有一個(gè)的執(zhí)行線程,即同一時(shí)刻內(nèi)只會(huì)有一段代碼在執(zhí)行。與單線程如何實(shí)現(xiàn)異步設(shè)計(jì)了一個(gè)事件循環(huán)的方式。
眾所周知,JavaScript(以下簡(jiǎn)稱(chēng) JS) 是單線程語(yǔ)言,在 html5 中增加了 web workers,web workers 是新開(kāi)了線程執(zhí)行的,那么 JS 還是單線程的嗎?當(dāng)然是,為什么要設(shè)計(jì)成單線程?
網(wǎng)上有很多說(shuō)法,大部分都說(shuō)是多個(gè)線程同時(shí)對(duì)一個(gè)dom操作(同時(shí)修改dom內(nèi)容,一個(gè)線程增加屬性,一個(gè)線程刪除屬性),會(huì)非常混亂,當(dāng)然如果支持多線程就會(huì)相應(yīng)的就要加入多線程的鎖機(jī)制,那么 JS 就變得非常復(fù)雜了,想想 JS 最開(kāi)始設(shè)計(jì)的初衷就是用于用戶(hù)交互,而且當(dāng)時(shí)的原始需求是:功能不需要太強(qiáng),語(yǔ)法較為簡(jiǎn)單,容易學(xué)習(xí)和部署,Brendan Eich 只用了10天,就設(shè)計(jì)完成了這種語(yǔ)言的第一版,因此也不可能加入多線程這么復(fù)雜的技術(shù)。
即使現(xiàn)在支持 web workers,由于沒(méi)有多線程的機(jī)制,web workers 和執(zhí)行線程只能通過(guò) postMessage 來(lái)通信,而且由于沒(méi)有鎖,web workers 無(wú)法訪問(wèn) window 和 document 對(duì)象。
Micro-Task 與 Macro-TaskJS 的單線程是指一個(gè)瀏覽器進(jìn)程中只有一個(gè) JS 的執(zhí)行線程,即同一時(shí)刻內(nèi)只會(huì)有一段代碼在執(zhí)行。
單線程如何實(shí)現(xiàn)異步?JS 設(shè)計(jì)了一個(gè)事件循環(huán)的方式。所有的代碼執(zhí)行均按照事件循環(huán)的方式進(jìn)行。
事件循環(huán)中分兩種任務(wù):一個(gè)是宏任務(wù)(Macro-Task),另一個(gè)是微任務(wù)(Micro-Task)。常見(jiàn)的宏任務(wù)和微任務(wù)如下。
宏任務(wù):script(整體代碼)、setTimeout、setInterval、requestAnimationFrame、I/O、事件、MessageChannel、setImmediate (Node.js) 微任務(wù):Promise.then、 MutaionObserver、process.nextTick (Node.js)
事件循環(huán)按下圖的方式進(jìn)行。
注意: 宏任務(wù)執(zhí)行完后,需要清空當(dāng)前微任務(wù)隊(duì)列后才回去執(zhí)行下一個(gè)宏任務(wù),如果微任務(wù)里面產(chǎn)生了新的微任務(wù),仍然會(huì)在當(dāng)前事件循環(huán)里面被執(zhí)行完,后面會(huì)舉例說(shuō)明。
來(lái)個(gè)示例驗(yàn)證下上面的流程。
<script>
console.log(1);
setTimeout(function timeout1() {
console.log(2);
}, 0);
Promise.resolve().then(function promise1() {
console.log(3);
setTimeout(function timeout2() {
console.log(4);
Promise.resolve().then(function promise2() {
console.log(5);
});
}, 0);
return Promise.resolve()
.then(function promise3() {
console.log(6);
return Promise.resolve().then(function promise4() {
console.log(7);
});
})
.then(function promise5() {
console.log(8);
});
})
console.log(9);
script>
<script>
console.log(10);
setTimeout(function timeout3() {
console.log(11);
}, 0);
Promise.resolve().then(function promise6() {
console.log(12);
});
script>
按照上面流程梳理下執(zhí)行流程:
將兩個(gè)宏任務(wù)(兩個(gè)script代碼)初始化進(jìn)宏任務(wù)隊(duì)列,宏任務(wù)隊(duì)列為:[script1, script2]
script1 出隊(duì)壓入執(zhí)行棧執(zhí)行,宏任務(wù)隊(duì)列為:[script2]
同步代碼執(zhí)行輸出:1,
timeout1 入隊(duì),宏任務(wù)隊(duì)列為:[script2, timeout1]
promise1 入隊(duì),微任務(wù)隊(duì)列為:[promise1]
同步代碼執(zhí)行輸出:9
script1 執(zhí)行完畢,進(jìn)入微任務(wù)執(zhí)行階段,promise1 出隊(duì)壓入執(zhí)行棧執(zhí)行,微任務(wù)隊(duì)列為空
同步代碼執(zhí)行輸出:3
timeout2 入隊(duì),宏任務(wù)隊(duì)列為:[script2, timeout1, timeout2]
promise3 入隊(duì),微任務(wù)隊(duì)列為:[promise3]
promise1 執(zhí)行完畢,繼續(xù)判斷微任務(wù)隊(duì)列是否為空,promise3 出隊(duì)壓入執(zhí)行棧執(zhí)行,微任務(wù)隊(duì)列為空
同步代碼執(zhí)行輸出:6
promise4 入隊(duì),微任務(wù)隊(duì)列為:[promise4]
promise3 執(zhí)行完畢,promise5 入隊(duì),微任務(wù)隊(duì)列為:[promise4,promise5]
判斷微任務(wù)隊(duì)列是否為空,promise4 出隊(duì)壓入執(zhí)行棧執(zhí)行,微任務(wù)隊(duì)列為:[promise5]
同步代碼執(zhí)行輸出:7
promise4 執(zhí)行完畢,繼續(xù)判斷微任務(wù)隊(duì)列是否為空,promise5 出隊(duì)壓入執(zhí)行棧執(zhí)行,微任務(wù)隊(duì)列為空
同步代碼執(zhí)行輸出:8
微任務(wù)隊(duì)列清空,宏任務(wù) script2 出隊(duì)壓入執(zhí)行棧執(zhí)行,宏任務(wù)隊(duì)列為[ timeout1, timeout2]
同步代碼執(zhí)行輸出:10
timeout3 入隊(duì),宏任務(wù)隊(duì)列為:[timeout1, timeout2, timeout3]
promise6 入隊(duì),微任務(wù)隊(duì)列為:[promise6]
script2 執(zhí)行完畢,進(jìn)入微任務(wù)執(zhí)行階段,promise6 出隊(duì)壓入執(zhí)行棧執(zhí)行,微任務(wù)隊(duì)列為空
同步代碼執(zhí)行輸出:12
微任務(wù)隊(duì)列為空,執(zhí)行宏任務(wù)隊(duì)列,timeout1 判斷是否到時(shí)間,timeout1 到時(shí)壓入執(zhí)行棧執(zhí)行,宏任務(wù)隊(duì)列為[ timeout2, timeout3]
同步代碼執(zhí)行輸出:2
微任務(wù)隊(duì)列為空,執(zhí)行宏任務(wù)隊(duì)列,timeout2 判斷是否到時(shí)間,timeout2 到時(shí)壓入執(zhí)行棧執(zhí)行,宏任務(wù)隊(duì)列為[ timeout3]
同步代碼執(zhí)行輸出:4,promise2 入隊(duì),微任務(wù)隊(duì)列為:[promise2]
timeout2 執(zhí)行完畢,判斷微任務(wù)隊(duì)列是否為空,promise2 出隊(duì)壓入執(zhí)行棧執(zhí)行,微任務(wù)隊(duì)列為空
同步代碼執(zhí)行輸出:5
微任務(wù)隊(duì)列為空,執(zhí)行宏任務(wù)隊(duì)列,timeout3 判斷是否到時(shí)間,timeout3 到時(shí)壓入執(zhí)行棧執(zhí)行,宏任務(wù)隊(duì)列為空
同步代碼執(zhí)行輸出:11
宏任務(wù)隊(duì)列為空
JavaScript語(yǔ)言的歷史
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/6834.html
摘要:深入理解引擎的執(zhí)行機(jī)制最近在反省,很多知識(shí)都是只會(huì)用,不理解底層的知識(shí)。在閱讀之前,請(qǐng)先記住兩點(diǎn)是單線程語(yǔ)言的是的執(zhí)行機(jī)制。所以,是存在異步執(zhí)行的,比如單線程是怎么實(shí)現(xiàn)異步的場(chǎng)景描述通過(guò)事件循環(huán),所以說(shuō),理解了機(jī)制,也就理解了的執(zhí)行機(jī)制啦。 深入理解js引擎的執(zhí)行機(jī)制 最近在反省,很多知識(shí)都是只會(huì)用,不理解底層的知識(shí)。所以在開(kāi)發(fā)過(guò)程中遇到一些奇怪的比較難解決的bug,在思考的時(shí)候就會(huì)收...
摘要:深入理解引擎的執(zhí)行機(jī)制靈魂三問(wèn)為什么是單線程的為什么需要異步單線程又是如何實(shí)現(xiàn)異步的呢中的中的說(shuō)說(shuō)首先請(qǐng)牢記點(diǎn)是單線程語(yǔ)言的是的執(zhí)行機(jī)制。 深入理解JS引擎的執(zhí)行機(jī)制 1.靈魂三問(wèn) : JS為什么是單線程的? 為什么需要異步? 單線程又是如何實(shí)現(xiàn)異步的呢? 2.JS中的event loop(1) 3.JS中的event loop(2) 4.說(shuō)說(shuō)setTimeout 首先,請(qǐng)牢記2...
摘要:曾經(jīng)的理解首先,是單線程語(yǔ)言,也就意味著同一個(gè)時(shí)間只能做一件事,那么為什么不是多線程呢這樣還能提高效率啊假定同時(shí)有兩個(gè)線程,一個(gè)線程在某個(gè)節(jié)點(diǎn)上編輯了內(nèi)容,而另一個(gè)線程刪除了這個(gè)節(jié)點(diǎn),這時(shí)瀏覽器就很懵逼了,到底以執(zhí)行哪個(gè)操作呢所以,設(shè)計(jì)者把 Event Loop曾經(jīng)的理解 首先,JS是單線程語(yǔ)言,也就意味著同一個(gè)時(shí)間只能做一件事,那么 為什么JavaScript不是多線程呢?這樣還能提...
摘要:的單線程,與它的用途有關(guān)。只要指定過(guò)回調(diào)函數(shù),這些事件發(fā)生時(shí)就會(huì)進(jìn)入任務(wù)隊(duì)列,等待主線程讀取。四主線程從任務(wù)隊(duì)列中讀取事件,這個(gè)過(guò)程是循環(huán)不斷的,所以整個(gè)的這種運(yùn)行機(jī)制又稱(chēng)為事件循環(huán)。令人困惑的是,文檔中稱(chēng),指定的回調(diào)函數(shù),總是排在前面。 原文:http://www.cnblogs.com/Master... 一、為什么JavaScript是單線程? JavaScript語(yǔ)言的一大特點(diǎn)...
摘要:圖片轉(zhuǎn)引自的演講和兩個(gè)定時(shí)器中回調(diào)的執(zhí)行邏輯便是典型的機(jī)制。異步編程關(guān)于異步編程我的理解是,在執(zhí)行環(huán)境所提供的異步機(jī)制之上,在應(yīng)用編碼層面上實(shí)現(xiàn)整體流程控制的異步風(fēng)格。 問(wèn)題背景 在一次開(kāi)發(fā)任務(wù)中,需要實(shí)現(xiàn)如下一個(gè)餅狀圖動(dòng)畫(huà),基于canvas進(jìn)行繪圖,但由于對(duì)于JS運(yùn)行環(huán)境中異步機(jī)制的不了解,所以遇到了一個(gè)棘手的問(wèn)題,始終無(wú)法解決,之后在與同事交流之后才恍然大悟。問(wèn)題的根節(jié)在于經(jīng)典的J...
摘要:中叫做調(diào)用棧先進(jìn)后出,后進(jìn)先出。如下圖這是典型的內(nèi)存溢出,可能會(huì)出現(xiàn)在某些場(chǎng)景下需要遞歸,但業(yè)務(wù)邏輯中的判斷又沒(méi)能正常計(jì)算進(jìn)入到預(yù)設(shè)情況,于是調(diào)用棧中不斷進(jìn)入,又無(wú)法執(zhí)行完,就造成內(nèi)存溢出了。 本文主要介紹Javascript事件循環(huán)在瀏覽器上的一些特性和應(yīng)用介紹。 Javascript小知識(shí) JavaScript的并發(fā)模型基于事件循環(huán)(Event Loop)。這個(gè)模型與像C或者Jav...
閱讀 2859·2021-11-24 09:39
閱讀 2842·2021-09-23 11:45
閱讀 3457·2019-08-30 12:49
閱讀 3429·2019-08-30 11:18
閱讀 2106·2019-08-29 16:42
閱讀 3400·2019-08-29 16:35
閱讀 1385·2019-08-29 11:21
閱讀 1985·2019-08-26 13:49