摘要:?jiǎn)尉€程的好處簡(jiǎn)單,處理時(shí)不會(huì)出現(xiàn)并發(fā)競(jìng)爭(zhēng)問(wèn)題異步的必要性讓用戶體驗(yàn)更流暢如何實(shí)現(xiàn)異步見(jiàn)參考,,調(diào)用棧函數(shù)執(zhí)行上下文。單線程只能有一個(gè)并且每次只能執(zhí)行一個(gè)任務(wù)。
參考:
JavaScript 運(yùn)行機(jī)制詳解:再談Event Loop
深入理解JavaScript的執(zhí)行過(guò)程--單線程的JS
細(xì)說(shuō)JavaScript單線程的一些事
The JavaScript Event Loop: Explained
模擬Event Loop執(zhí)行過(guò)程
Node.js 事件循環(huán)一: 淺析
理解 Event Loop、Micro Task & Macro Task
HTML系列:macrotask和microtask
1. js為啥是單線程執(zhí)行單線程是指只在一個(gè)線程里執(zhí)行JS代碼,但瀏覽器是多線程的。
1.1 單線程的好處簡(jiǎn)單,處理DOM時(shí)不會(huì)出現(xiàn)并發(fā)競(jìng)爭(zhēng)問(wèn)題
2. 異步的必要性讓用戶體驗(yàn)更流暢
3. 如何實(shí)現(xiàn)異步:Event Loop見(jiàn)參考1,4,5
函數(shù)執(zhí)行上下文。控制執(zhí)行函數(shù)的調(diào)用執(zhí)行。單線程只能有一個(gè)call statck, 并且每次只能執(zhí)行一個(gè)任務(wù)。棧是有尺寸的,即在一次執(zhí)行中函數(shù)的嵌套調(diào)用數(shù)量是有限的,如果超過(guò)這個(gè)限制就會(huì)報(bào)錯(cuò)。JS執(zhí)行時(shí)遇到這種錯(cuò)誤"Uncaught RangeError: Maximum call stack size exceeded"就是說(shuō)明call statck溢出了。回調(diào)函數(shù)上限數(shù)量取決于statck本身的大小以及statck元素的大小->見(jiàn)參考:
function computeMaxCallStackSize1() { try { return 1 + computeMaxCallStackSize1(); } catch (e) { // Call stack overflow return 1; } } // 多了形參p,call stack元素就多占了內(nèi)存 function computeMaxCallStackSize2(p) { try { return 1 + computeMaxCallStackSize2(); } catch (e) { // Call stack overflow return 1; } } console.log(computeMaxCallStackSize1()); // 兩個(gè)輸出結(jié)果不一樣 console.log(computeMaxCallStackSize2());3.2 回調(diào)隊(duì)列(callback queue)
看參考圖,生動(dòng)的動(dòng)畫模擬可以見(jiàn)參考5。當(dāng)call stack空的時(shí)候,主線程查看callback隊(duì)列里是否有異步任務(wù),如果有則取出執(zhí)行,執(zhí)行完后(即call stack變空了)再去查看call back隊(duì)列是否有異步任務(wù)。這個(gè)是循環(huán)的過(guò)程,也叫事件循環(huán)(event loop)。
while (queue.waitForMessage()) { queue.processNextMessage(); }
個(gè)人認(rèn)為事件隊(duì)列主要實(shí)現(xiàn)了異步回調(diào)功能。
3.3 非阻塞I/O首先明確一點(diǎn),JS本身就沒(méi)有I/O(網(wǎng)絡(luò)請(qǐng)求,磁盤讀寫,用戶交互)的,所有的I/O操作都是由宿主執(zhí)行的,宿主提供相關(guān)的API供JS調(diào)用。當(dāng)JS調(diào)用IO API時(shí)并不會(huì)等待宿主的執(zhí)行結(jié)果而是繼續(xù)執(zhí)行后面的代碼,當(dāng)IO執(zhí)行完成后宿主再通知JS,即在eventQueue中插入回調(diào)task。
不過(guò)還有些I/O是同步的,比如同步XHR請(qǐng)求,alert。盡量避免使用。
event loop實(shí)現(xiàn)了異步回調(diào),但回調(diào)只能一個(gè)一個(gè)的執(zhí)行,但前面的一個(gè)回調(diào)非常耗時(shí)時(shí)就會(huì)阻塞后面的回調(diào)執(zhí)行,用戶交互也可能出現(xiàn)卡死。
function sleep(ms) { var curr = Date.now(); while(Date.now() - curr < ms){}; } console.log(1) setTimeout(function(){ // 回調(diào)依舊被阻塞 console.log(2) }, 0) sleep(2000)
最好開(kāi)啟新線程執(zhí)行耗時(shí)的運(yùn)算(使用web worker)或者放在服務(wù)端運(yùn)算。
4. Macro-task & micro-taskevent loop中除了 callback queue(macro-task)外還有個(gè)隊(duì)列專門處理micro-task。micor-task隊(duì)列為空時(shí)才去處理macro-task隊(duì)列執(zhí)行。
當(dāng)打算以同步的方式處理異步回調(diào)(即執(zhí)行棧為空時(shí)立馬執(zhí)行回調(diào)函數(shù))時(shí)可以采用micro-task方式。
macrotasks: setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering
microtasks: process.nextTick, Promises, Object.observe, MutationObserver
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/93324.html
摘要:通過(guò)向消息池發(fā)送各種消息事件通過(guò)處理相應(yīng)的消息事件。子線程往消息隊(duì)列發(fā)送消息,并且往管道文件寫數(shù)據(jù),主線程即被喚醒,從管道文件讀取數(shù)據(jù),主線程被喚醒只是為了讀取消息,當(dāng)消息讀取完畢,再次睡眠。 目錄介紹 6.0.0.1 談?wù)勏C(jī)制Hander作用?有哪些要素?流程是怎樣的? 6.0.0.2 為什么一個(gè)線程只有一個(gè)Looper、只有一個(gè)MessageQueue,可以有多個(gè)Handle...
閱讀 3065·2021-09-22 15:59
閱讀 1316·2021-08-30 09:46
閱讀 2280·2019-08-30 15:54
閱讀 2014·2019-08-26 12:15
閱讀 2540·2019-08-26 12:09
閱讀 1341·2019-08-26 11:57
閱讀 3340·2019-08-23 17:11
閱讀 1889·2019-08-23 15:59