摘要:全部代碼是一個先執行一個執行過程中遇到等異步操作則創建一個遇到等創建一個這兩個分別被掛起執行棧為空時開始處理完成后處理直到該全部執行完然后繼續主線程調用棧注每一次事件循環,只處理一個。
JS異步原理(事件,隊列) 調用棧
JS執行時會形成調用棧,調用一個函數時,返回地址、參數、本地變量都會被推入棧中,如果當前正在運行的函數中調用另外一個函數,則該函數相關內容也會被推入棧頂.該函數執行完畢,則會被彈出調用棧.變量也隨之彈出,由于復雜類型值存放于堆中,因此彈出的只是指針,他們的值依然在堆中,由GC決定回收.
尾調用:指某個函數的最后一步是調用另一個函數。由調用棧可知,調用棧中有a函數,如果a函數調用b函數,則b函數也隨之入棧,此時棧中就會有兩個函數.但是如果b函數是a函數最后一步,并且不需保留外層函數調用記錄,即a函數調用位置變量等都不需要用到,則該調用棧中會只保留b函數,這就叫做"尾調用優化"(Tail call optimization),即只保留內層函數的調用記錄。如果所有函數都是尾調用,那么完全可以做到每次執行時,調用記錄只有一項,這將大大節省內存。這就是"尾調用優化"的意義。
function a() { let m = 1; let n = 2; return b(m + n); } a(); // 等同于 function a() { return b(3); } a(); // 等同于 b(3);事件循環(event loop)和任務隊列(task queue)
JS的異步機制由事件循環和任務隊列構成.JS本身是單線程語言,所謂異步依賴于瀏覽器或者操作系統等完成. JavaScript 主線程擁有一個執行棧以及一個任務隊列,主線程會依次執行代碼,當遇到函數時,會先將函數入棧,函數運行完畢后再將該函數出棧,直到所有代碼執行完畢。
遇到異步操作(例如:setTimeout, AJAX)時,異步操作會由瀏覽器(OS)執行,瀏覽器會在這些任務完成后,將事先定義的回調函數推入主線程的任務隊列(task queue)中,當主線程的執行棧清空之后會讀取task queue中的回調函數,當task queue被讀取完畢之后,主線程接著執行,從而進入一個無限的循環,這就是事件循環.
Microtask 與 MacrotaskHowever, we only have one main thread and one call-stack, so in case there is another request being served when the said file is read, its callback will need to wait for the stack to become empty. The limbo where callbacks are waiting for their turn to be executed is called the task queue (or event queue, or message queue). Callbacks are being called in an infinite loop whenever the main thread has finished its previous task, hence the name "event loop".
一個瀏覽器環境(unit of related similar-origin browsing contexts.)只能有一個事件循環(Event loop),而一個事件循環可以多個任務隊列(Task queue),每個任務都有一個任務源(Task source)。例如,客戶端可能實現了一個包含鼠標鍵盤事件的任務隊列,還有其他的任務隊列,而給鼠標鍵盤事件的任務隊列更高優先級,例如75%的可能性執行它。這樣就能保證流暢的交互性,而且別的任務也能執行到了。但是,同一個任務隊列中的任務必須按先進先出的順序執行。多個任務隊列,是為了方便控制優先級。任務隊列是一個先進先出的隊列.
macrotask 和 microtask 是異步任務的兩種分類。在掛起任務時,JS 引擎會將所有任務按照類別分到這兩個隊列中,首先在 macrotask 的隊列(這個隊列也被叫做 task queue)中取出第一個任務,執行完畢后取出 microtask 隊列中的所有任務順序執行;之后再取 macrotask 任務,周而復始,直至兩個隊列的任務都取完。
全部代碼(script)是一個macrotask,js先執行一個macrotask,執行過程中遇到(setTimeout, setInterval, setImmediate等)異步操作則創建一個macrotask,遇到(process.nextTick, Promises等)創建一個microtask,這兩個queue分別被掛起.執行棧為空時開始處理macrotask,完成后處理microtask,直到該microtask全部執行完,然后繼續主線程調用棧.
注:每一次事件循環(one cycle of the event loop),只處理一個 (macro)task。待該 macrotask 完成后,所有的 microtask 會在同一次循環中處理。處理這些 microtask 時,還可以將更多的 microtask 入隊,它們會一一執行,直到整個 microtask 隊列處理完。
兩個類別的具體分類如下:
macro-task: script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, Promises(這里指瀏覽器實現的原生 Promise), Object.observe, MutationObserver
參考文章:
Promise的隊列與setTimeout的隊列有何關聯?
node事件循環
深入淺出JavaScript事件循環機制(下)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85044.html
摘要:全部代碼是一個先執行一個執行過程中遇到等異步操作則創建一個遇到等創建一個這兩個分別被掛起執行棧為空時開始處理完成后處理直到該全部執行完然后繼續主線程調用棧注每一次事件循環,只處理一個。 JS異步原理(事件,隊列) 調用棧 JS執行時會形成調用棧,調用一個函數時,返回地址、參數、本地變量都會被推入棧中,如果當前正在運行的函數中調用另外一個函數,則該函數相關內容也會被推入棧頂.該函數執...
摘要:全部代碼是一個先執行一個執行過程中遇到等異步操作則創建一個遇到等創建一個這兩個分別被掛起執行棧為空時開始處理完成后處理直到該全部執行完然后繼續主線程調用棧注每一次事件循環,只處理一個。 JS異步原理(事件,隊列) 調用棧 JS執行時會形成調用棧,調用一個函數時,返回地址、參數、本地變量都會被推入棧中,如果當前正在運行的函數中調用另外一個函數,則該函數相關內容也會被推入棧頂.該函數執...
摘要:我們可以為元素添加屬性然后在回調函數中接受該元素在樹中的句柄,該值會作為回調函數的第一個參數返回。使用最常見的用法就是傳入一個對象。單向數據流,比較有序,有便于管理,它隨著視圖庫的開發而被概念化。 面試中問框架,經常會問到一些原理性的東西,明明一直在用,也知道怎么用, 但面試時卻答不上來,也是挺尷尬的,就干脆把react相關的問題查了下資料,再按自己的理解整理了下這些答案。 reac...
摘要:道阻且長啊前端面試總結前端面試筆試面試騰訊一面瀏覽器工作原理瀏覽器的主要組件包括用戶界面包括地址欄后退前進按鈕書簽目錄瀏覽器引擎用來查詢及操作渲染引擎的接口渲染引擎渲染界面和是基于兩種渲染引擎構建的,使用自主研發的渲染引擎,和都使用網絡用來 道阻且長啊TAT(前端面試總結) 前端 面試 筆試 面試 騰訊一面 1.瀏覽器工作原理 瀏覽器的主要組件包括: 用戶界面- 包括地址欄、后退/前...
閱讀 2000·2023-04-25 16:53
閱讀 1442·2021-10-13 09:39
閱讀 606·2021-09-08 09:35
閱讀 1639·2019-08-30 13:03
閱讀 2121·2019-08-30 11:06
閱讀 1831·2019-08-30 10:59
閱讀 3188·2019-08-29 17:00
閱讀 2288·2019-08-23 17:55