中國空間站拒絕10國名單h5頁面制作軟件手機版
鶴壁市浩天電氣有限公司
2026/01/24 19:13:33
中國空間站拒絕10國名單,h5頁面制作軟件手機版,wordpress 分類字段,wordpress刪除所有評論你以為JavaScript是單線程的#xff0c;但它卻用事件循環(huán)實現(xiàn)了偽異步。理解宏任務(wù)和微任務(wù)#xff0c;是掌握現(xiàn)代前端異步編程的關(guān)鍵。引言#xff1a;從一道經(jīng)典面試題說起javascriptconsole.log(1);setTimeout(() {console.log(2);
}, 0);Promise.resol…你以為JavaScript是單線程的但它卻用事件循環(huán)實現(xiàn)了偽異步。理解宏任務(wù)和微任務(wù)是掌握現(xiàn)代前端異步編程的關(guān)鍵。引言從一道經(jīng)典面試題說起javascriptconsole.log(1); setTimeout(() { console.log(2); }, 0); Promise.resolve().then(() { console.log(3); }); console.log(4); // 輸出順序是什么如果你的答案是1, 4, 3, 2那么恭喜你已經(jīng)理解了事件循環(huán)的基本概念。但事件循環(huán)遠不止于此...第一部分JavaScript運行環(huán)境的真相1.1 為什么JavaScript是單線程的JavaScript最初被設(shè)計為瀏覽器腳本語言主要用于處理DOM操作。多線程同時操作DOM會帶來復(fù)雜的同步問題。因此JavaScript采用了單線程事件循環(huán)的模型。javascript// 瀏覽器中的JavaScript執(zhí)行環(huán)境 ┌───────────────────────────┐ │ JavaScript │ ← 單線程執(zhí)行 │ Engine (V8/SpiderMonkey)│ └───────────────────────────┘ ↑ ↓ ┌───────────────────────────┐ │ Web APIs (瀏覽器提供) │ ← 異步APIsetTimeout、DOM事件、Ajax等 └───────────────────────────┘ ↑ ↓ ┌───────────────────────────┐ │ Task Queue (任務(wù)隊列) │ ← 待執(zhí)行的回調(diào)函數(shù) └───────────────────────────┘1.2 事件循環(huán)的基本原理javascript// 事件循環(huán)的簡化模型 while (eventLoop.waitForTask()) { // 1. 從任務(wù)隊列中取出一個任務(wù) const task eventLoop.getNextTask(); // 2. 執(zhí)行任務(wù) try { task(); } catch (error) { console.error(任務(wù)執(zhí)行出錯:, error); } // 3. 執(zhí)行所有微任務(wù) eventLoop.processMicrotasks(); // 4. 渲染如果需要 if (shouldRender()) { eventLoop.render(); } }第二部分宏任務(wù) vs 微任務(wù)2.1 什么是宏任務(wù)宏任務(wù)MacroTask代表一個獨立的、完整的工作單元。每個宏任務(wù)執(zhí)行完后瀏覽器可能會進行渲染。常見的宏任務(wù)script整體代碼setTimeout / setIntervalsetImmediateNode.jsI/O操作UI渲染瀏覽器事件回調(diào)click、load等MessageChanneljavascript// 宏任務(wù)示例 console.log(腳本開始); // 這是第一個宏任務(wù) setTimeout(() { console.log(setTimeout回調(diào)); // 新的宏任務(wù) }, 0); button.addEventListener(click, () { console.log(按鈕點擊); // 事件回調(diào)是宏任務(wù) }); // 當(dāng)前宏任務(wù)結(jié)束2.2 什么是微任務(wù)微任務(wù)MicroTask是在當(dāng)前宏任務(wù)結(jié)束后、下一個宏任務(wù)開始前立即執(zhí)行的任務(wù)。微任務(wù)隊列會在每個宏任務(wù)執(zhí)行完畢后清空。常見的微任務(wù)Promise.then / .catch / .finallyasync/await本質(zhì)是PromiseMutationObserver瀏覽器process.nextTickNode.js優(yōu)先級最高queueMicrotask APIjavascript// 微任務(wù)示例 console.log(開始); Promise.resolve().then(() { console.log(Promise 1); // 微任務(wù) }).then(() { console.log(Promise 2); // 微任務(wù) }); queueMicrotask(() { console.log(queueMicrotask); // 微任務(wù) }); console.log(結(jié)束); // 輸出開始 → 結(jié)束 → Promise 1 → Promise 2 → queueMicrotask2.3 完整的執(zhí)行順序javascript// 完整的事件循環(huán)順序示例 console.log(1 - 同步代碼宏任務(wù)開始); setTimeout(() { console.log(2 - setTimeout宏任務(wù)); Promise.resolve().then(() { console.log(3 - 內(nèi)層Promise微任務(wù)); }); }, 0); Promise.resolve().then(() { console.log(4 - 外層Promise微任務(wù)); setTimeout(() { console.log(5 - 內(nèi)層setTimeout宏任務(wù)); }, 0); }); console.log(6 - 同步代碼宏任務(wù)結(jié)束); // 執(zhí)行順序分析 // 1. 執(zhí)行當(dāng)前宏任務(wù)整體代碼輸出 1, 6 // 2. 執(zhí)行微任務(wù)隊列輸出 4 // 3. 執(zhí)行下一個宏任務(wù)第一個setTimeout輸出 2 // 4. 執(zhí)行該宏任務(wù)產(chǎn)生的微任務(wù)輸出 3 // 5. 執(zhí)行下一個宏任務(wù)第二個setTimeout輸出 5第三部分瀏覽器與Node.js的事件循環(huán)差異3.1 瀏覽器的事件循環(huán)模型javascript// 瀏覽器事件循環(huán)階段 ┌───────────────────────┐ │ 宏任務(wù)隊列 │ │ 1. 執(zhí)行一個宏任務(wù) │ └──────────┬────────────┘ │ ┌──────────▼────────────┐ │ 微任務(wù)隊列 │ │ 2. 執(zhí)行所有微任務(wù) │ └──────────┬────────────┘ │ ┌──────────▼────────────┐ │ requestAnimation │ │ 3. 執(zhí)行RAF回調(diào) │ └──────────┬────────────┘ │ ┌──────────▼────────────┐ │ 渲染階段 │ │ 4. 樣式計算、布局、繪制 │ └──────────┬────────────┘ │ ┌──────────▼────────────┐ │ requestIdleCallback │ │ 5. 執(zhí)行RIC回調(diào)空閑時│ └───────────────────────┘3.2 Node.js的事件循環(huán)模型javascript// Node.js事件循環(huán)階段更復(fù)雜 ┌───────────────────────────┐ │ timers階段 │ ← 執(zhí)行setTimeout/setInterval回調(diào) └─────────────┬─────────────┘ │ ┌─────────────▼─────────────┐ │ pending callbacks階段 │ ← 執(zhí)行上一輪未執(zhí)行的I/O回調(diào) └─────────────┬─────────────┘ │ ┌─────────────▼─────────────┐ │ idle, prepare階段 │ ← 內(nèi)部使用 └─────────────┬─────────────┘ │ ┌─────────────▼─────────────┐ │ poll階段 │ ← 檢索新的I/O事件執(zhí)行相關(guān)回調(diào) └─────────────┬─────────────┘ │ ┌─────────────▼─────────────┐ │ check階段 │ ← 執(zhí)行setImmediate回調(diào) └─────────────┬─────────────┘ │ ┌─────────────▼─────────────┐ │ close callbacks階段 │ ← 執(zhí)行close事件的回調(diào) └───────────────────────────┘3.3 關(guān)鍵差異對比javascript// 差異1process.nextTick vs Promise Promise.resolve().then(() { console.log(Promise); }); process.nextTick(() { console.log(nextTick); // 先執(zhí)行 }); // 差異2setTimeout vs setImmediate setTimeout(() { console.log(timeout); }, 0); setImmediate(() { console.log(immediate); // 順序不確定取決于當(dāng)前執(zhí)行環(huán)境 }); // 差異3瀏覽器 vs Node.js的微任務(wù)執(zhí)行時機 setTimeout(() { console.log(timeout1); Promise.resolve().then(() { console.log(promise1); }); }, 0); setTimeout(() { console.log(timeout2); Promise.resolve().then(() { console.log(promise2); }); }, 0); // 瀏覽器輸出timeout1 → promise1 → timeout2 → promise2 // Node.js可能輸出timeout1 → timeout2 → promise1 → promise2第四部分實戰(zhàn)應(yīng)用場景4.1 性能優(yōu)化避免阻塞渲染javascript// 不好大量同步任務(wù)阻塞渲染 function processLargeArray(array) { const results []; for (let i 0; i array.length; i) { // 昂貴的計算 results.push(expensiveCalculation(array[i])); } return results; } // 好將任務(wù)分解為多個宏任務(wù) function processLargeArrayAsync(array, chunkSize 100) { return new Promise((resolve) { const results []; let index 0; function processChunk() { const end Math.min(index chunkSize, array.length); for (; index end; index) { results.push(expensiveCalculation(array[index])); } if (index array.length) { // 使用setTimeout讓出控制權(quán)允許渲染 setTimeout(processChunk, 0); } else { resolve(results); } } processChunk(); }); } // 更好使用微任務(wù)避免不必要的渲染 function processLargeArrayMicrotask(array, chunkSize 100) { return new Promise((resolve) { const results []; let index 0; function processChunk() { const end Math.min(index chunkSize, array.length); for (; index end; index) { results.push(expensiveCalculation(array[index])); } if (index array.length) { // 使用queueMicrotask在當(dāng)前任務(wù)結(jié)束后立即執(zhí)行 queueMicrotask(processChunk); } else { resolve(results); } } processChunk(); }); }4.2 實現(xiàn)優(yōu)先級調(diào)度javascriptclass TaskScheduler { constructor() { this.microTasks []; this.macroTasks []; this.isProcessing false; } // 添加高優(yōu)先級任務(wù)微任務(wù) addMicrotask(task) { this.microTasks.push(task); this.scheduleRun(); } // 添加普通任務(wù)宏任務(wù) addMacrotask(task) { this.macroTasks.push(task); this.scheduleRun(); } scheduleRun() { if (this.isProcessing) return; this.isProcessing true; // 使用微任務(wù)來啟動處理 queueMicrotask(() { this.processTasks(); }); } processTasks() { // 先處理所有微任務(wù) while (this.microTasks.length 0) { const task this.microTasks.shift(); try { task(); } catch (error) { console.error(微任務(wù)執(zhí)行失敗:, error); } } // 然后處理一個宏任務(wù) if (this.macroTasks.length 0) { const task this.macroTasks.shift(); try { task(); } catch (error) { console.error(宏任務(wù)執(zhí)行失敗:, error); } } // 如果還有任務(wù)繼續(xù)調(diào)度 if (this.microTasks.length 0 || this.macroTasks.length 0) { this.scheduleRun(); } else { this.isProcessing false; } } } // 使用示例 const scheduler new TaskScheduler(); scheduler.addMacrotask(() console.log(宏任務(wù) 1)); scheduler.addMicrotask(() console.log(微任務(wù) 1)); scheduler.addMacrotask(() console.log(宏任務(wù) 2)); scheduler.addMicrotask(() console.log(微任務(wù) 2)); // 輸出微任務(wù) 1 → 微任務(wù) 2 → 宏任務(wù) 1 → 宏任務(wù) 24.3 實現(xiàn)防抖與節(jié)流的升級版javascript// 使用微任務(wù)優(yōu)化的防抖 function debounceMicrotask(fn, delay) { let timerId null; let microtaskQueued false; return function(...args) { const context this; // 清除之前的定時器 if (timerId) { clearTimeout(timerId); } // 如果沒有微任務(wù)在排隊創(chuàng)建一個 if (!microtaskQueued) { microtaskQueued true; queueMicrotask(() { microtaskQueued false; // 設(shè)置新的定時器 timerId setTimeout(() { fn.apply(context, args); timerId null; }, delay); }); } }; } // 使用示例 const expensiveSearch debounceMicrotask((query) { console.log(搜索:, query); // 實際搜索邏輯 }, 300); // 快速連續(xù)輸入 expensiveSearch(a); expensiveSearch(ab); expensiveSearch(abc); // 只執(zhí)行最后一次4.4 React中的批量更新javascript// React利用事件循環(huán)實現(xiàn)狀態(tài)批量更新 class FakeReact { constructor() { this.state {}; this.isBatchingUpdates false; this.pendingStates []; } setState(newState) { if (this.isBatchingUpdates) { // 如果在批處理中收集狀態(tài)更新 this.pendingStates.push(newState); } else { // 否則直接更新 this.applyUpdate(newState); } } batchedUpdates(callback) { this.isBatchingUpdates true; try { callback(); } finally { this.isBatchingUpdates false; // 在微任務(wù)中執(zhí)行所有收集的更新 if (this.pendingStates.length 0) { queueMicrotask(() { const states [...this.pendingStates]; this.pendingStates []; states.forEach(state { this.applyUpdate(state); }); }); } } } applyUpdate(newState) { this.state { ...this.state, ...newState }; console.log(狀態(tài)更新:, this.state); } } // 使用示例 const react new FakeReact(); react.batchedUpdates(() { react.setState({ count: 1 }); react.setState({ count: 2 }); react.setState({ count: 3 }); }); // 只會觸發(fā)一次更新{ count: 3 }第五部分常見陷阱與最佳實踐5.1 微任務(wù)無限遞歸javascript// 危險的代碼微任務(wù)無限循環(huán) function dangerousMicrotaskLoop() { Promise.resolve().then(() { console.log(微任務(wù)執(zhí)行); dangerousMicrotaskLoop(); // 遞歸調(diào)用 }); } // 這會阻塞事件循環(huán)導(dǎo)致頁面無響應(yīng) // 因為微任務(wù)隊列永遠不會清空 // 安全的方式使用宏任務(wù) function safeMacrotaskLoop() { console.log(宏任務(wù)執(zhí)行); setTimeout(safeMacrotaskLoop, 0); // 允許渲染 }5.2 混合使用宏任務(wù)和微任務(wù)javascript// 不推薦的模式 button.addEventListener(click, () { // 宏任務(wù)中產(chǎn)生微任務(wù) Promise.resolve().then(() { // 微任務(wù)中又產(chǎn)生宏任務(wù) setTimeout(() { // 難以追蹤執(zhí)行順序 console.log(多層嵌套); }, 0); }); }); // 推薦的模式保持清晰的任務(wù)層次 async function handleClick() { // 步驟1微任務(wù)處理 await processImmediate(); // 步驟2宏任務(wù)處理 setTimeout(() { processDelayed(); }, 0); } button.addEventListener(click, handleClick);5.3 最佳實踐總結(jié)優(yōu)先使用微任務(wù)對于需要立即執(zhí)行但不阻塞渲染的任務(wù)適時使用宏任務(wù)對于可以延遲執(zhí)行或需要允許渲染的任務(wù)避免微任務(wù)遞歸防止微任務(wù)隊列永不空合理使用async/await理解其基于Promise微任務(wù)的本質(zhì)考慮使用queueMicrotask比Promise.resolve().then()更語義化注意執(zhí)行順序在混合使用時要清晰了解執(zhí)行順序第六部分現(xiàn)代API與事件循環(huán)6.1 requestAnimationFramejavascript// requestAnimationFrame在渲染前執(zhí)行 console.log(開始); setTimeout(() { console.log(setTimeout); }, 0); requestAnimationFrame(() { console.log(requestAnimationFrame); }); Promise.resolve().then(() { console.log(Promise); }); console.log(結(jié)束); // 典型輸出開始 → 結(jié)束 → Promise → requestAnimationFrame → setTimeout // 但注意RAF在渲染前執(zhí)行時機可能因瀏覽器而異6.2 requestIdleCallbackjavascript// 在空閑時間執(zhí)行低優(yōu)先級任務(wù) function processIdleTasks(deadline) { while (tasks.length 0 deadline.timeRemaining() 0) { const task tasks.shift(); task(); } if (tasks.length 0) { requestIdleCallback(processIdleTasks); } } // 與事件循環(huán)的配合 button.addEventListener(click, () { // 高優(yōu)先級任務(wù)立即執(zhí)行 console.log(點擊處理); // 低優(yōu)先級任務(wù)在空閑時執(zhí)行 requestIdleCallback(() { console.log(空閑任務(wù)); }); });6.3 MutationObserverjavascript// MutationObserver使用微任務(wù) const observer new MutationObserver((mutations) { console.log(DOM變化, mutations); }); observer.observe(document.body, { childList: true, subtree: true }); // 測試 setTimeout(() { document.body.appendChild(document.createElement(div)); console.log(添加元素后); }, 0); // 輸出順序添加元素后 → DOM變化 // MutationObserver回調(diào)作為微任務(wù)執(zhí)行總結(jié)掌握事件循環(huán)的藝術(shù)事件循環(huán)是JavaScript異步編程的核心機制理解宏任務(wù)和微任務(wù)的差異對于編寫高性能、響應(yīng)迅速的前端應(yīng)用至關(guān)重要。關(guān)鍵要點宏任務(wù)是獨立的執(zhí)行完一個宏任務(wù)后會執(zhí)行所有微任務(wù)微任務(wù)是緊接的在當(dāng)前宏任務(wù)結(jié)束后立即執(zhí)行渲染時機通常在微任務(wù)執(zhí)行完畢后下一個宏任務(wù)開始前優(yōu)先級同步代碼 微任務(wù) 渲染 宏任務(wù)何時使用什么微任務(wù)需要立即執(zhí)行的狀態(tài)更新、Promise處理、數(shù)據(jù)同步宏任務(wù)需要延遲執(zhí)行的任務(wù)、I/O操作、用戶交互處理requestAnimationFrame與渲染相關(guān)的動畫、視覺更新requestIdleCallback低優(yōu)先級的后臺任務(wù)記住事件循環(huán)不是JavaScript引擎的特性而是宿主環(huán)境瀏覽器/Node.js提供的機制。不同的宿主環(huán)境可能有不同的實現(xiàn)但核心概念相通。通過深入理解事件循環(huán)你不僅能寫出更好的異步代碼還能更有效地調(diào)試性能問題構(gòu)建更流暢的用戶體驗。