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