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