摘要:為了利用多核的計算能力,提出標(biāo)準(zhǔn),允許腳本創(chuàng)建多個線程,但是子線程完全受主線程控制,且不得操作。所以,這個新標(biāo)準(zhǔn)并沒有改變單線程的本質(zhì)。
從一個例子說起
var start = new Date() setTimeout(function () { var end = new Date console.log("Time elapsed:", end - start, "ms") }, 500) while (new Date() - start < 1000) { }
有其他語言能完成預(yù)期的功能嗎?Java, 在Java.util.Timer中,對于定時任務(wù)的解決方案是通過多線程手段實現(xiàn)的,任務(wù)對象存儲在任務(wù)隊列,由專門的調(diào)度線程,在新的子線程中完成任務(wù)的執(zhí)行
js是單線程的JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。
為了利用多核CPU的計算能力,HTML5提出Web Worker標(biāo)準(zhǔn),允許JavaScript腳本創(chuàng)建多個線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個新標(biāo)準(zhǔn)并沒有改變JavaScript單線程的本質(zhì)。
函數(shù)調(diào)用棧和任務(wù)隊列 調(diào)用棧JS執(zhí)行時會形成調(diào)用棧,調(diào)用一個函數(shù)時,返回地址、參數(shù)、本地變量都會被推入棧中,如果當(dāng)前正在運行的函數(shù)中調(diào)用另外一個函數(shù),則該函數(shù)相關(guān)內(nèi)容也會被推入棧頂.該函數(shù)執(zhí)行完畢,則會被彈出調(diào)用棧.變量也隨之彈出,由于復(fù)雜類型值存放于堆中,因此彈出的只是指針,他們的值依然在堆中,由GC決定回收.
事件循環(huán)(event loop) & 任務(wù)隊列(task queue)JavaScript 主線程擁有一個執(zhí)行棧以及一個任務(wù)隊列
遇到異步操作(例如:setTimeout, AJAX)時,異步操作會由瀏覽器(OS)執(zhí)行,瀏覽器會在這些任務(wù)完成后,將事先定義的回調(diào)函數(shù)推入主線程的任務(wù)隊列(task queue)中,當(dāng)主線程的執(zhí)行棧清空之后會讀取task queue中的回調(diào)函數(shù),當(dāng)task queue被讀取完畢之后,主線程接著執(zhí)行,從而進(jìn)入一個無限的循環(huán),這就是事件循環(huán).
主線程執(zhí)行棧 & 任務(wù)隊列 循環(huán)執(zhí)行,構(gòu)成事件循環(huán)
結(jié)論setTimeout()只是將事件插入了"任務(wù)隊列",必須等到當(dāng)前代碼(執(zhí)行棧)執(zhí)行完,主線程才會去執(zhí)行它指定的回調(diào)函數(shù)。要是當(dāng)前代碼耗時很長,有可能要等很久,所以并沒有辦法保證,回調(diào)函數(shù)一定會在setTimeout()指定的時間執(zhí)行。
另一個例子(function test() { setTimeout(function() {console.log(4)}, 0); new Promise(function executor(resolve) { console.log(1); for( var i=0 ; i<10000 ; i++ ) { i == 9999 && resolve(); } console.log(2); }).then(function() { console.log(5); }); console.log(3); })()Macrotask & Microtask
macrotask 和 microtask 是異步任務(wù)的兩種分類。在掛起任務(wù)時,JS 引擎會將所有任務(wù)按照類別分到這兩個隊列中,首先在 macrotask 的隊列(這個隊列也被叫做 task queue)中取出第一個任務(wù),執(zhí)行完畢后取出 microtask 隊列中的所有任務(wù)順序執(zhí)行;之后再取 macrotask 任務(wù),周而復(fù)始,直至兩個隊列的任務(wù)都取完。
macro-task: script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, Promises(這里指瀏覽器實現(xiàn)的原生 Promise), Object.observe, MutationObserver
結(jié)論全部代碼(script) macrotask -> microtask queue (含有promise.then) -> macrotask(setTimeout) -> 下一個microtask
Node.js的事件循環(huán) process.nextTick & setImmediateprocess.nextTick指定的任務(wù)總是發(fā)生在所有異步任務(wù)之前
setImmediate指定的任務(wù)總是在下一次Event Loop時執(zhí)行
process.nextTick(function A() { console.log(1); process.nextTick(function B(){console.log(2);}); }); setTimeout(function timeout() { console.log("TIMEOUT FIRED"); }, 0)
new Promise(function(resolve) { console.log("glob1_promise"); resolve(); }).then(function() { console.log("glob1_then") }) process.nextTick(function() { console.log("glob1_nextTick"); })總結(jié)
通過學(xué)習(xí)函數(shù)調(diào)用棧,任務(wù)隊列,MacroTask, MicroTask等概念,對js中的事件循環(huán)機制有更深的理解,在以后面對setTimeout, setInterval等異步操作時,更清晰的理解其運行機制,避免寫出不可控的代碼。
參考鏈接:https://zhuanlan.zhihu.com/p/...
https://zhuanlan.zhihu.com/p/...
http://www.ruanyifeng.com/blo...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/92058.html
摘要:主線程不斷重復(fù)上面的三步,此過程也就是常說的事件循環(huán)。所以主線程代碼執(zhí)行時間過長,會阻塞事件循環(huán)的執(zhí)行。參考資料這一次,徹底弄懂執(zhí)行機制任務(wù)隊列的順序機制事件循環(huán)搞懂異步事件輪詢與中的事件循環(huán) 1. 說明 讀過本文章后,您能知道: JavaScript代碼在瀏覽器中的執(zhí)行機制和事件循環(huán) 面試中經(jīng)常遇到的代碼輸出順序問題 首先通過一段代碼來驗證你是否了解代碼輸出順序,如果你不知道輸出...
摘要:主線程要明確的一點是,主線程跟執(zhí)行棧是不同概念,主線程規(guī)定現(xiàn)在執(zhí)行執(zhí)行棧中的哪個事件。主線程循環(huán)即主線程會不停的從執(zhí)行棧中讀取事件,會執(zhí)行完所有棧中的同步代碼。以上參考資料詳解中的事件循環(huán)機制中的事件循環(huán)運行機制詳解再談 showImg(https://segmentfault.com/img/remote/1460000015317437?w=1920&h=1080); 前言 大家都...
摘要:前沿是基于引擎的運行環(huán)境具有事件驅(qū)動非阻塞等特點結(jié)合具有網(wǎng)絡(luò)編程文件系統(tǒng)等服務(wù)端的功能用庫進(jìn)行異步事件處理線程的單線程含義實際上說的是執(zhí)行同步代碼的主線程一個程序的啟動不止是分配了一個線程,而是我們只能在一個線程執(zhí)行代碼當(dāng)出現(xiàn)資源調(diào)用連接等 前沿 Node.js 是基于V8引擎的javascript運行環(huán)境. Node.js具有事件驅(qū)動, 非阻塞I/O等特點. 結(jié)合Node API, ...
摘要:事件循環(huán)機制事件循環(huán)機制分為瀏覽器和事件循環(huán)機制,兩者的實現(xiàn)技術(shù)不一樣,瀏覽器是中定義的規(guī)范,是由庫實現(xiàn)。整個事件循環(huán)完成之后,會去檢測微任務(wù)的任務(wù)隊列中是否存在任務(wù),存在就執(zhí)行。 文章來自我的 github 博客,包括技術(shù)輸出和學(xué)習(xí)筆記,歡迎star。 先來明白些概念性內(nèi)容。 進(jìn)程、線程 進(jìn)程是系統(tǒng)分配的獨立資源,是 CPU 資源分配的基本單位,進(jìn)程是由一個或者多個線程組成的。 線...
摘要:如果沒有其他異步任務(wù)要處理比如到期的定時器,會一直停留在這個階段,等待請求返回結(jié)果。執(zhí)行的執(zhí)行事件關(guān)閉請求的,例如事件循環(huán)的每一次循環(huán)都需要依次經(jīng)過上述的階段。因此,才會早于執(zhí)行。 showImg(https://segmentfault.com/img/bVbnY76); 概念 同步任務(wù)(Synchronous) 在主線程上排隊執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù) ...
摘要:事件循環(huán)機制首先區(qū)分進(jìn)程和線程進(jìn)程是資源分配的最小單位系統(tǒng)會給它分配內(nèi)存不同的進(jìn)程之間是可以同學(xué)的,如管道命名管道消息隊列一個進(jìn)程里有單個或多個線程瀏覽器是多進(jìn)程的,因為系統(tǒng)給它的進(jìn)程分配了資源內(nèi)存打開會有一個主進(jìn)程,每打開一個頁就有一個獨 JS JavaScript事件循環(huán)機制 首先區(qū)分進(jìn)程和線程 進(jìn)程是cpu資源分配的最小單位(系統(tǒng)會給它分配內(nèi)存) 不同的進(jìn)程之間是可以同學(xué)的,如...
閱讀 1924·2021-11-23 09:51
閱讀 1360·2021-11-18 10:02
閱讀 993·2021-10-25 09:44
閱讀 2133·2019-08-26 18:36
閱讀 1655·2019-08-26 12:17
閱讀 1178·2019-08-26 11:59
閱讀 2769·2019-08-23 15:56
閱讀 3386·2019-08-23 15:05