MutationObserver 回調是作為任務或微任務同步或異步調用的?如果出現異常怎么辦?
在前端開發中,監控DOM變化是一項常見需求,無論是用于模擬用戶操作還是動態調整頁面內容。隨著Chrome 127移除了傳統的mutation
事件(如DOMNodeInserted和DOMNodeRemoved),MutationObserver成為了DOM監控的首選API。本文將深入探討MutationObserver的工作機制,特別關注其回調執行的時機和異常處理方式。
MutationObserver的核心特性
- 異步回調:MutationObserver的回調是作為微任務(microtask)執行的。
- 變更合并:多個同步DOM變更會被合并到一個回調中處理。
- 異常處理:回調中拋出的異常不會中斷觀察者的運行。
實驗驗證
以下代碼片段展示了MutationObserver的關鍵行為:
function callback(mutations) {
console.log('變更:', mutations.flatMap(m => [...m.addedNodes].map(n => n.nodeValue)));
throw '回調中的異常';
}
const observer = new MutationObserver(callback);
observer.observe(root, { childList: true });
setTimeout(() => console.log('前置宏任務'));
Promise.resolve().then(() => console.log('前置微任務'));
for (let i = 0; i < 3; i++) {
const text = `節點${i}; `;
root.append(text);
console.log('已添加: ' + text);
}
setTimeout(() => console.log('后置宏任務'));
Promise.resolve().then(() => console.log('后置微任務'));
運行結果分析:
圖片
- 三個同步DOM變更被合并到一個回調中。
- 回調在兩個預定的微任務之間執行,證實其作為普通微任務的性質。
- 預定的宏任務在微任務隊列清空后執行。
- 回調中拋出的異常不影響后續操作。
實際應用示例
考慮一個動態加載內容的網頁場景:
function contentObserver(mutations) {
for (let mutation of mutations) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE && node.classList.contains('dynamic-content')) {
processNewContent(node);
}
});
}
}
}
const observer = new MutationObserver(contentObserver);
observer.observe(document.body, { childList: true, subtree: true });
function processNewContent(node) {
// 處理新加載的內容
console.log('處理新內容:', node);
}
// 模擬動態加載內容
setTimeout(() => {
const newContent = document.createElement('div');
newContent.classList.add('dynamic-content');
newContent.textContent = '新加載的內容';
document.body.appendChild(newContent);
}, 1000);
這個例子展示了如何使用MutationObserver監控動態加載的內容,并在新內容添加時進行處理。
結語
MutationObserver提供了一種強大而高效的方式來監控DOM變化。了解其作為微任務執行、變更合并和異常處理的特性,可以幫助開發者更好地設計和實現DOM監控邏輯。在實際應用中,合理利用這些特性可以優化性能,并實現更復雜的DOM交互功能。