JavaScript 的非同步特性在您深入研究其機制之前可能會讓人感覺很神奇。秘密在於它的事件循環,它協調兩個關鍵角色:微任務和宏任務。但它們是什麼、它們如何運作以及為什麼它們重要?讓我們透過深入研究、範例和技巧來解開這個謎團,以掌握這個概念。
JavaScript 引擎在單一執行緒中執行程式碼。為了處理非同步操作,它依賴事件循環,它在呼叫堆疊和任務佇列之間進行協調。這些任務隊列分為兩類:微任務和宏任務。
微任務是高優先權任務,必須在目前執行的 JavaScript 程式碼完成且呼叫堆疊為空時立即執行。它們確保快速的後續行動和一致的狀態。常見範例包括:
巨集任務是優先順序較低的任務,事件循環僅在所有微任務執行完畢後才處理。它們處理更大的、延遲的操作和外部事件。常見範例包括:
還有 requestAnimationFrame,它不屬於任一佇列。它與瀏覽器的渲染週期同步,非常適合流暢的動畫。
以下是事件循環處理任務的方式:
這種優先順序確保先解決諸如承諾之類的高優先級任務,然後再解決諸如計時器之類的不太緊急的操作。
下面是一個實用的程式碼片段,用來說明同步程式碼、微任務、巨集任務和 requestAnimationFrame 之間的互動:
console.log('Synchronous code starts'); // Macrotask: setTimeout setTimeout(() => { console.log('Macrotask: setTimeout'); }, 0); // Macrotask: setInterval const intervalId = setInterval(() => { console.log('Macrotask: setInterval'); clearInterval(intervalId); }, 100); // Microtask: Promise Promise.resolve().then(() => { console.log('Microtask: Promise then 1'); Promise.resolve().then(() => { console.log('Microtask: Promise then 2'); }); }); // Microtask: MutationObserver const observer = new MutationObserver(() => { console.log('Microtask: MutationObserver'); }); const targetNode = document.createElement('div'); observer.observe(targetNode, { attributes: true }); targetNode.setAttribute('data-test', 'true'); // Macrotask: MessageChannel const channel = new MessageChannel(); channel.port1.onmessage = () => { console.log('Macrotask: MessageChannel'); }; channel.port2.postMessage('Test'); // requestAnimationFrame requestAnimationFrame(() => { console.log('Outside task queues: requestAnimationFrame'); }); console.log('Synchronous code ends');
輸出序列有助於闡明優先順序:
雖然不是任務佇列的一部分,requestAnimationFrame 在非同步中發揮著獨特的作用。它安排程式碼在下一次瀏覽器重繪之前運行,確保最少的幀丟失和更流暢的動畫。
微任務、巨集任務和事件循環之間的交互作用是 JavaScript 非同步的核心。透過理解和利用這些概念,您可以編寫更有效率、可維護和高效能的程式碼。請記住:首先是微任務,其次是巨集任務,然後使用 requestAnimationFrame 進行視覺美化。快樂編碼!
以上是深入探討非同步:微任務、巨集任務與事件循環的詳細內容。更多資訊請關注PHP中文網其他相關文章!