最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript運行機制、v8原理、js事件循環(huán)過程

 更新時間:2026年06月06日 09:55:04   作者:Hello--_--World  
了解JavaScript引擎與運行機制,包括解釋型與編譯型語言的區(qū)別,JIT技術如何提升性能,以及JavaScript的單線程特性與異步任務處理機制,通過解析、解釋、監(jiān)控與優(yōu)化等步驟,現(xiàn)代JavaScript引擎如如V8,實現(xiàn)了高效的代碼執(zhí)行

一、有了解過JavaScript引擎嗎?

JavaScript運行機制有沒有詳細了解過?請詳細說明

1. JavaScript是解釋型語言還是編譯型語言?

1.1 編譯型 vs. 解釋型:核心差異

我們可以把編程語言想象成一份外文食譜,為了讓計算機(只會二進制)讀懂,我們需要不同的翻譯方式:

編譯型語言 (Compiled)

  • 過程:在程序運行之前,先由編譯器 (Compiler) 將整個源代碼一次性翻譯成機器語言(如 Windows 下的 .exe)。
  • 代表:C、C++、Go、Rust。

特點

  • 運行快:運行時無需翻譯,直接執(zhí)行機器碼。
  • 不靈活:即使改動一行代碼,也需要重新編譯整個程序。
  • 平臺依賴:在 Windows 上編譯的程序通常無法直接在 Linux 上運行。

解釋型語言 (Interpreted)

  • 過程:程序運行時,由解釋器 (Interpreter) 一行一行地讀取源代碼,“翻譯”一行就“執(zhí)行”一行。
  • 代表:Python、Ruby、早期的 JavaScript。

特點

  • 運行慢:邊譯邊跑,翻譯過程會占用實際運行時間。
  • 靈活:跨平臺性好,只要系統(tǒng)安裝了對應的解釋器,代碼即可運行。

1.2 JavaScript 屬于哪一種?

結(jié)論:現(xiàn)代 JavaScript 是一種采用 JIT (Just-In-Time) 即時編譯技術的動態(tài)語言。

雖然傳統(tǒng)上 JS 被視為“解釋型腳本語言”,但現(xiàn)代 JS 引擎(如 Chrome 的 V8)為了極致的性能,早已進化為混合模式。它不再是單純地逐行翻譯,而是通過 JIT 技術在運行過程中動態(tài)優(yōu)化代碼。

1.3 什么是 JIT(即時編譯)?

JIT 結(jié)合了編譯型和解釋型的優(yōu)點,旨在解決“解釋器太慢”和“編譯器啟動久”的痛點。

JIT 的工作流程:

  1. 快速響應:代碼加載時,解釋器首先介入,快速開始執(zhí)行,讓用戶感知不到延遲。
  2. 熱點探測:在運行過程中,引擎會監(jiān)控哪些代碼塊被頻繁執(zhí)行(稱為 Hot Spot / 熱點代碼)。
  3. 即時編譯JIT 編譯器將這些熱點代碼直接編譯為高效的機器碼。
  4. 替換執(zhí)行:當再次遇到相同代碼時,直接調(diào)用編譯好的機器碼,跳過解釋步驟。

性能 ≈ 解釋器的響應速度 + 編譯器的執(zhí)行效率 性能 \approx 解釋器的響應速度 + 編譯器的執(zhí)行效率 性能解釋器的響應速度+編譯器的執(zhí)行效率

1.4 核心特性對比表

特性編譯型 (Compiled)解釋型 (Interpreted)JIT (現(xiàn)代 JS / JVM)
翻譯時機程序運行前運行時 (逐行翻譯)運行時 (按需編譯)
執(zhí)行速度極快較慢接近原生速度
啟動速度慢 (需等待編譯完成)
跨平臺性較低 (需重新編譯)極高
典型代表C++, Rust, GoPython, PHPJavaScript (V8), Java

進階知識:

現(xiàn)代 JS 引擎甚至擁有 “去優(yōu)化 (Deoptimization)” 機制。如果 JIT 編譯器根據(jù)之前的運行數(shù)據(jù)做出了錯誤的優(yōu)化假設(例如本以為某個變量總是數(shù)字,結(jié)果突然變成了字符串),引擎會立即丟棄已優(yōu)化的機器碼,回退到解釋器模式,以確保程序的正確性。

2. 深度解析:JavaScript 引擎 (JS Engine)

2.1 什么是 JavaScript 引擎?

JavaScript 引擎是一個專門負責解析、解釋并執(zhí)行 JavaScript 代碼的程序。

如果把瀏覽器比作一輛汽車,那么 JavaScript 引擎就是這輛車的發(fā)動機。它的核心任務是:將人類可讀的高級代碼(JS)轉(zhuǎn)換為計算機 CPU 能夠理解并運行的二進制機器指令。

2.2 主流引擎概覽

不同的環(huán)境和瀏覽器使用不同的引擎,但它們都遵循 ECMAScript 標準:

引擎名稱開發(fā)者主要應用環(huán)境
V8GoogleChrome, Node.js, Electron, Edge
SpiderMonkeyMozillaFirefox
JavaScriptCoreAppleSafari, iOS 全線應用
ChakraMicrosoft早期 Edge, IE (已逐步退出舞臺)

2.3 引擎內(nèi)部是如何工作的? (以 V8 為例)

現(xiàn)代引擎的工作流程并不是簡單的“翻譯”,而是一個復雜的流水線:

解析 (Parsing)

  • 引擎將源碼拆解為 Tokens (記號)。
  • 生成 AST (Abstract Syntax Tree, 抽象語法樹),這是代碼的結(jié)構(gòu)化表示。

解釋 (Interpretation)

  • 解釋器(V8 中的 Ignition)將 AST 轉(zhuǎn)換為中間形態(tài)的 字節(jié)碼 (Bytecode) 并開始執(zhí)行。這一步保證了代碼能以最快速度啟動。

編譯與優(yōu)化 (JIT Compilation)

  • 引擎會監(jiān)控運行狀態(tài)。如果某段代碼運行非常頻繁(Hot Spot / 熱點代碼),編譯器(V8 中的 TurboFan)會將其直接編譯為高性能的機器碼

垃圾回收 (Garbage Collection)

  • 引擎內(nèi)置管理機制,自動識別并釋放不再使用的內(nèi)存空間。

2.4 為什么要理解引擎原理?

  • 性能優(yōu)化:了解引擎如何識別“熱點代碼”,可以避免寫出觸發(fā)“去優(yōu)化 (Deoptimization)”的代碼(例如頻繁改變對象屬性結(jié)構(gòu))。
  • 內(nèi)存管理:理解引擎如何分配內(nèi)存,能更好地規(guī)避內(nèi)存泄漏問題。
  • 底層視野:這是從“調(diào)包俠”邁向“架構(gòu)師/高級工程師”的必經(jīng)之路,也是技術面試(尤其是字節(jié)、騰訊等大廠)的??純?nèi)容。

核心要點:

JavaScript 引擎并不是獨立的,它運行在宿主環(huán)境(如瀏覽器或 Node.js)中。引擎只負責執(zhí)行 JS,而 DOM 操作、網(wǎng)絡請求(AJAX)、定時器(setTimeout)是由宿主環(huán)境提供的 Web APIs 或內(nèi)置模塊處理的。

3. 深度解析:瀏覽器引擎 (Browser Engine / Rendering Engine)

3.1 什么是瀏覽器引擎?

如果說 JS 引擎 是汽車的“發(fā)動機”,那么 瀏覽器引擎(也稱渲染引擎)就是整臺車的“底盤與組裝車間”。

它的核心職責是:讀取 HTML、CSS 和圖像資源,經(jīng)過一系列復雜的計算,最終將網(wǎng)頁內(nèi)容像素化并繪制在用戶的屏幕上。

3.2 三足鼎立:主流引擎分布

目前市面上絕大多數(shù)瀏覽器都基于以下三大引擎構(gòu)建:

引擎名稱主要開發(fā)者代表瀏覽器特點
BlinkGoogle / 社區(qū)Chrome, Edge, OperaWebKit 的分支,目前生態(tài)位最強,性能優(yōu)異。
WebKitAppleSafari, 所有 iOS 瀏覽器注重能效比,是蘋果生態(tài)系統(tǒng)的唯一準入引擎。
GeckoMozillaFirefox堅持獨立開發(fā),高度尊重隱私與 Web 標準。

3.3 渲染流水線 (Rendering Pipeline)

瀏覽器引擎將代碼轉(zhuǎn)化為圖像的過程被稱為 關鍵渲染路徑 (Critical Rendering Path)

解析 (Parsing)

  • 解析 HTML → 生成 DOM 樹。
  • 解析 CSS → 生成 CSSOM 樹。

構(gòu)建渲染樹 (Render Tree)

  • 將 DOM 與 CSSOM 合并。引擎會過濾掉不需要顯示的元素(如 display: none)。

布局 (Layout / Reflow)

  • 計算每個節(jié)點在屏幕上的確切幾何位置(高、寬、坐標)。

繪制 (Painting)

  • 將渲染樹中的每個節(jié)點轉(zhuǎn)換成屏幕上的實際像素點。

合成 (Compositing)

  • 將網(wǎng)頁的各個圖層(Layers)按正確順序疊加,生成最終圖像。

3.4 瀏覽器引擎 vs. JS 引擎 的協(xié)作

兩者雖各司其職,但在運行過程中緊密配合:

  • 渲染中斷:當瀏覽器引擎解析 HTML 遇到 <script> 標簽時,會暫停渲染,等待 JS 引擎 執(zhí)行完腳本。
  • 雙向通信:JS 引擎通過 DOM API 修改網(wǎng)頁內(nèi)容,瀏覽器引擎接收到指令后觸發(fā) 重排(Reflow)重繪(Repaint)

3.5 開發(fā)者為何必須掌握它?

  • 性能調(diào)優(yōu):理解布局(Layout)比繪制(Paint)更耗性能,可以減少不必要的頁面卡頓。
  • 解決兼容性:了解不同引擎對 CSS 特性的實現(xiàn)差異(如 -webkit- 前綴的由來)。
  • 面試深度:它是大廠面試題“從輸入 URL 到頁面顯示發(fā)生了什么”的核心環(huán)節(jié)。

黃金公式:

瀏覽器 (Browser) = 瀏覽器引擎 (Blink/WebKit) + JS 引擎 (V8/JSC) + 網(wǎng)絡模塊 + UI 界面 + 各類 Web API。

4. 深度解析:V8 引擎如何執(zhí)行 JavaScript 代碼

4.1 解析階段 (Parsing)

當 V8 接收到源碼字符串后,會進行兩步預處理:

詞法分析 (Scanner):

詞法分析是解析的第一步,它的核心目標是:“識字”并“切分”。

切分單詞(Tokenizing):將一連串的源碼字符流拆分成一個個具有獨立語義的單元,稱為 Token(詞法單元)。

  • 例如:let a = 10; 會被拆分為 let (關鍵字), a (變量名), = (賦值符), 10 (數(shù)字), ; (分隔符)。

過濾雜質(zhì):自動剔除代碼中對邏輯運行無意義的內(nèi)容,如空格、換行符、注釋等。

初步分類與轉(zhuǎn)換:將字符串轉(zhuǎn)換為內(nèi)部編號(ID)。對于引擎來說,處理數(shù)字 1(代表關鍵字 let)比處理字符串 “let” 要快得多。

詞法錯誤檢查:發(fā)現(xiàn)不符合詞法規(guī)則的字符。例如在 JS 中寫了一個非法的特殊符號,詞法分析階段就會報錯。

語法分析 (Parser):

語法分析是解析的第二步,它的核心目標是:“組句”并“建樹”。

構(gòu)建 AST(抽象語法樹):將詞法分析產(chǎn)出的平鋪的 Token 序列,根據(jù)語言的語法規(guī)則(文法)組裝成一棵樹狀結(jié)構(gòu)。這棵樹展示了代碼之間的層級和邏輯關系。

  • 例如:它會識別出 a = 10 是一個“賦值表達式”,其中 a 是左值,10 是右值。

驗證語法合法性:檢查 Token 的排列順序是否符合 JS 語法。

  • 詞法分析能認出 let、=、;,但只有語法分析能告訴你 let = ; 是錯誤的排布。

確定作用域與語義:在建樹的過程中,解析器會初步確定變量的作用域(全局還是局部),并為后續(xù)生成字節(jié)碼提供邏輯依據(jù)。

4.2 解釋階段 (Interpretation)

  • 角色Ignition 解釋器
  • 動作:將 AST 轉(zhuǎn)換為 Bytecode (字節(jié)碼) 并立即開始執(zhí)行。
  • 優(yōu)勢:字節(jié)碼生成速度極快,且比機器碼占用更少的內(nèi)存,保證了網(wǎng)頁的“首屏加載速度”。

4.3 監(jiān)控與分析 (Profiling)

  • 在代碼運行期間,V8 會啟動一個 Profiler 監(jiān)聽運行狀態(tài)。
  • 它會尋找那些被多次調(diào)用的函數(shù)或循環(huán),將其標記為 “Hot Spot” (熱點代碼)。

4.4 優(yōu)化編譯 (JIT Compilation)

  • 角色TurboFan 編譯器
  • 動作:將“熱點代碼”的字節(jié)碼直接編譯為 Optimized Machine Code (優(yōu)化機器碼)。
  • 結(jié)果:機器碼是二進制指令,CPU 直接讀取執(zhí)行,運行速度接近 C++ 原生水平。

4.5 去優(yōu)化 (Deoptimization)

  • 原理:JS 是動態(tài)類型語言。如果 TurboFan 假設某個變量一直是數(shù)字并進行了優(yōu)化,但運行中它突然變成了字符串。
  • 處理:引擎會立即撤銷優(yōu)化(Deopt),回退到 Ignition 解釋器執(zhí)行字節(jié)碼,確保邏輯正確性。

總結(jié):V8 的執(zhí)行流水線

狀態(tài)處理過程產(chǎn)物特點
初始源碼讀取字符串人類可讀
分析ParsingAST 樹邏輯結(jié)構(gòu)化
啟動Ignition字節(jié)碼響應快、內(nèi)存省
加速TurboFan機器碼執(zhí)行快、性能高

開發(fā)者啟示

了解這個過程后,你會發(fā)現(xiàn):保持變量類型的一致性(不要隨意改變對象屬性的類型或結(jié)構(gòu))能顯著減少“去優(yōu)化”的發(fā)生,讓代碼始終運行在 TurboFan 的“高速公路”上。

5 JS 引擎的運行機制與環(huán)境隔離

5.1 為什么“解釋型”語言也需要先“掃描”代碼?

雖然 JavaScript 是即時編譯(JIT)語言,但它在執(zhí)行前必須經(jīng)過 Parser(解析器) 的全量掃描。

  • 語法安全檢查:在代碼運行前發(fā)現(xiàn) SyntaxError(如括號不匹配),防止程序運行到一半崩潰,保證執(zhí)行的原子性。
  • 構(gòu)建 AST (抽象語法樹):將純文本轉(zhuǎn)為機器能理解的邏輯樹,這是后續(xù)生成字節(jié)碼的必備前提。
  • 預分配內(nèi)存 (Hoisting):在掃描階段,引擎需要識別出所有的變量聲明,從而在內(nèi)存中提前開辟空間。

5.2 環(huán)境隔離:變量環(huán)境 vs. 詞法環(huán)境

為了在兼容老舊 var 代碼的同時,完美支持 ES6 的 let/const 塊級作用域,V8 將執(zhí)行上下文拆分為兩個獨立的存儲區(qū)域:

變量環(huán)境 (Variable Environment)

  • 存放內(nèi)容var 聲明的變量、函數(shù)聲明。
  • 設計目的:維護傳統(tǒng)的函數(shù)作用域
  • 底層行為:在創(chuàng)建階段,變量會被初始化為 undefined(產(chǎn)生變量提升現(xiàn)象)。

詞法環(huán)境 (Lexical Environment)

  • 存放內(nèi)容let、const 聲明的變量、with 語句、try...catch。
  • 設計目的:支持塊級作用域。
  • 底層行為:在創(chuàng)建階段,變量僅被記錄名稱,不進行初始化(產(chǎn)生暫時性死區(qū) TDZ)。

5.3 “物理隔離”帶來的深遠影響

這種設計決定了 JavaScript 在運行時的三個核心表現(xiàn):

查找順序

當訪問一個變量時,引擎優(yōu)先查找當前上下文的詞法環(huán)境,若無,再查找變量環(huán)境,最后順著作用域鏈向上尋找。這保證了塊級變量優(yōu)先于函數(shù)級變量。

塊級作用域的實現(xiàn)

在執(zhí)行過程中,每進入一個 {} 塊,詞法環(huán)境都會創(chuàng)建一個小型環(huán)境棧(Stack),并在退出塊時將其銷毀。這解決了 var 變量容易污染全局或循環(huán)體的問題。

暫時性死區(qū) (TDZ)

由于詞法環(huán)境中的變量在聲明前處于“未初始化”狀態(tài),任何提前訪問都會觸發(fā)錯誤。這迫使開發(fā)者養(yǎng)成“先聲明后使用”的良好習慣。

核心總結(jié)表

特性變量環(huán)境 (var)詞法環(huán)境 (let/const)
提升行為提升聲明并初始化為 undefined提升聲明但不初始化
作用域單位函數(shù) (Function Scope)塊 ({}) (Block Scope)
重復聲明允許禁止
訪問限制自由訪問(可能拿到 undefined)嚴格限制(TDZ 報錯)

底層思考

這種“雙環(huán)境”設計是現(xiàn)代 JS 引擎為了兼顧歷史兼容性現(xiàn)代語言特性而做出的工程妥協(xié),也是其性能與靈活性并存的秘密武器。

二、JavaScript 是單線程還是多線程?

請問異步任務處理機制是怎么樣的?分別說明瀏覽器與 Node 的事件循環(huán)機制

1. 核心定性:JavaScript 到底是不是單線程?

結(jié)論:JavaScript 語言執(zhí)行是單線程的,但其運行宿主環(huán)境(瀏覽器/Node.js)是多線程的。

  • 為什么單線程? 主要為了避免復雜的 DOM 操作沖突(如:線程 A 刪除節(jié)點,線程 B 修改節(jié)點)。
  • 如何處理異步? JS 引擎遇到異步任務(定時器、網(wǎng)絡請求)時,會將其交給瀏覽器的其他線程(渲染線程、HTTP 線程、定時器線程、事件觸發(fā)線程(處理點擊、滾動事件))處理。處理完成后,回調(diào)函數(shù)會進入“任務隊列”等待執(zhí)行。

2. 異步任務全家桶 (全面清單)

異步任務根據(jù)執(zhí)行優(yōu)先級的不同,分為 宏任務 (Macrotask)微任務 (Microtask)

微任務 (Microtask) —— 優(yōu)先級最高

執(zhí)行時機:當前調(diào)用棧清空后,立即執(zhí)行,且必須清空整個微任務隊列,才會進行下一次渲染或執(zhí)行宏任務。

  • Promise.then() / catch() / finally()
  • async / await (本質(zhì)是 Promise 的語法糖)
  • process.nextTick (Node.js 特有,微任務中的“王者”,優(yōu)先級高于 Promise)
  • MutationObserver (瀏覽器端,監(jiān)聽 DOM 變化)
  • queueMicrotask() (手動開啟微任務的官方 API)

宏任務 (Macrotask) —— 優(yōu)先級次之

執(zhí)行時機:由宿主環(huán)境發(fā)起。每輪事件循環(huán)只取出一個宏任務執(zhí)行。

  • script (整體代碼塊,是第一個宏任務)
  • setTimeout / setInterval
  • setImmediate (Node.js 特有)
  • I/O 操作 (文件讀寫、網(wǎng)絡請求回調(diào)、數(shù)據(jù)庫操作)
  • UI Rendering (瀏覽器特有,每輪循環(huán)結(jié)束后視情況觸發(fā))
  • postMessage / MessageChannel

3. 事件循環(huán) (Event Loop) 執(zhí)行模型

瀏覽器的執(zhí)行順序

  1. 執(zhí)行同步代碼(屬于第一個宏任務)。
  2. 同步代碼執(zhí)行完,檢查并清空整個微任務隊列。
  3. (視情況) 進行 UI 渲染。
  4. 從宏任務隊列中取入一個任務執(zhí)行。
  5. 回到步驟 2,循環(huán)往復。

Node.js 的執(zhí)行順序 (libuv)

Node.js 10+ 后與瀏覽器基本一致,但其底層分為 6 個階段循環(huán):

  1. timers:執(zhí)行 setTimeout 等回調(diào)。
  2. pending callbacks:執(zhí)行某些系統(tǒng)操作的回調(diào)。
  3. idle, prepare:內(nèi)部使用。
  4. poll (輪詢):處理 I/O 回調(diào),這是最核心階段。
  5. check:執(zhí)行 setImmediate 的回調(diào)。
  6. close callbacks:執(zhí)行關閉回調(diào)(如 socket.on('close'))。

4. 高頻面試避坑指南 (Killer Points)

Q1:Promise 內(nèi)部是異步的嗎?

坑點new Promise((resolve) => { ... }) 括號里的代碼是同步執(zhí)行的!只有 .then() 里面的回調(diào)才是異步微任務。

Q2:await 后面代碼的執(zhí)行順序?

坑點await 這一行右邊的表達式會立即執(zhí)行。而 await 下方的代碼會被阻塞,并存入微任務隊列(相當于 .then)。

黃金總結(jié)

一個宏任務 → \rightarrow 所有微任務 → \rightarrow 渲染 → \rightarrow 下一個宏任務。

5. 異步任務調(diào)度題

// 作業(yè)題 console.log('stack [1]');
console.log('stack [1]'); 

setTimeout(() => console.log("macro [2]"), 0);
setTimeout(() => console.log("macro [3]"), 1);

const p = Promise.resolve();
for(let i = 0; i < 3; i++) {
    p.then(() => {
        setTimeout(() => {
            console.log('stack [4]')
            setTimeout(() => console.log("macro [5]"), 0);
            p.then(() => console.log('micro [6]'));
        }, 0);
        console.log("stack [7]");
    });
}

console.log("stack [8]"); 

5.1 第一輪:執(zhí)行同步代碼(第一個宏任務)

此時,代碼從上到下掃一遍,同步代碼直接進入 調(diào)用棧 執(zhí)行,異步任務分發(fā)到各自隊列。

  • 第 1 行:打印 stack [1]。
  • 第 2, 3 行:遇到 setTimeout,將 macro [2] 和 macro [3] 分發(fā)到 宏任務隊列
  • 第 6-15 行:循環(huán) 3 次。p.then 是異步的,將三個 then 回調(diào)依次放入 微任務隊列(標記為 micro A, B, C)。
  • 第 17 行:打印 stack [8]。

當前狀態(tài):

  • 控制臺輸出:stack [1] → \rightarrow stack [8]
  • 微任務隊列:[micro A, micro B, micro C]
  • 宏任務隊列:[macro [2], macro [3]]

5.2 第二輪:清空微任務隊列(核心環(huán)節(jié))

步代碼跑完,調(diào)用??樟?,事件循環(huán)立即去清空所有的微任務。

執(zhí)行 micro A:

  • 內(nèi)部同步代碼:打印 stack [7](循環(huán)第 1 次)。
  • 內(nèi)部異步:遇到 setTimeout,將 stack [4] 的那個回調(diào)推入 宏任務隊列。

執(zhí)行 micro B:

  • 內(nèi)部同步代碼:打印 stack [7](循環(huán)第 2 次)。
  • 內(nèi)部異步:又將一個 stack [4] 推入 宏任務隊列。

執(zhí)行 micro C:內(nèi)部同步代碼:

  • 打印 stack [7](循環(huán)第 3 次)。
  • 內(nèi)部異步:再將一個 stack [4] 推入 宏任務隊列。

當前狀態(tài):

  • 控制臺輸出:…stack [8] → \rightarrow stack [7] → \rightarrow stack [7] → \rightarrow stack [7]
  • 微任務隊列:空
  • 宏任務隊列:[macro [2], macro [3], stack [4]-A, stack [4]-B, stack [4]-C]

5.3 第三輪:開始執(zhí)行宏任務

微任務清空后,事件循環(huán)取宏任務隊列中的 第一個 任務出來執(zhí)行。

  • 執(zhí)行 macro [2]:打印 macro [2]。
  • 執(zhí)行 macro [3]:打印 macro [3]。

執(zhí)行第一個 stack [4]-A:

  • 同步代碼:打印 stack [4]。
  • 異步嵌套1:setTimeout,將 macro [5] 推入宏任務隊列末尾。
  • 異步嵌套2:p.then,將 micro [6] 推入 微任務隊列。

注意! 宏任務執(zhí)行完,會立即檢查并清空微任務隊列。所以此時會先打印 micro [6],再跑下一個宏任務。

以此類推,執(zhí)行完 B 和 C 組。

5.4 最終輸出順序結(jié)果

為了方便你核對,最終的打印順序如下:

  1. stack [1]
  2. stack [8]
  3. stack [7] (循環(huán)1次)
  4. stack [7] (循環(huán)2次)
  5. stack [7] (循環(huán)3次)
  6. macro [2]
  7. macro [3]
  8. stack [4] (A組)
  9. micro [6] (A組微任務優(yōu)先執(zhí)行)
  10. stack [4] (B組)
  11. micro [6] (B組微任務優(yōu)先執(zhí)行)
  12. stack [4] (C組)
  13. micro [6] (C組微任務優(yōu)先執(zhí)行)
  14. macro [5] (A組嵌套)
  15. macro [5] (B組嵌套)
  16. macro [5] (C組嵌套)

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

最新評論

双辽市| 贞丰县| 朝阳区| 保山市| 三门县| 抚顺市| 大同市| 邯郸县| 西贡区| 克拉玛依市| 察隅县| 博白县| 灵璧县| 巴马| 雅安市| 上杭县| 岫岩| 瓦房店市| 宁陕县| 广饶县| 孝义市| 平顶山市| 白沙| 夏邑县| 繁昌县| 旌德县| 永定县| 神池县| 山阴县| 安庆市| 德保县| 南川市| 阿克| SHOW| 濮阳县| 泊头市| 渝中区| 呼图壁县| 洪洞县| 温宿县| 东辽县|