Chrome扩展开发中如何等待Mutation Observer响应后继续JS for循环
Chrome扩展遍历元素时等待MutationObserver回调的实现方案
这个需求完全可以实现,核心是将原有的同步for循环改为异步迭代模式,用Promise封装MutationObserver的监听逻辑,让循环在触发按钮点击后暂停执行,直到监听到预期的DOM变更、拿到所需数据后再继续下一轮迭代。
实现步骤
- 第一步:封装MutationObserver监听的Promise工具函数
把MutationObserver的监听逻辑封装成返回Promise的函数,当监听到符合预期的DOM变更时resolve Promise,即可配合await实现等待效果。
示例代码:// 入参:要监听的目标元素、判断是否为预期变更的校验函数 function waitForTargetMutation(observeElem, validateCallback) { return new Promise((resolve) => { const observer = new MutationObserver((mutations, observerInstance) => { // 每次DOM变更触发回调时,校验是否已经拿到需要的数据 if (validateCallback(mutations)) { // 拿到数据后停止监听,避免内存泄漏 observerInstance.disconnect(); // resolve Promise,结束等待 resolve(); } }); // 配置监听的变更类型,可根据实际需求调整,这里示例监听子节点、属性、子树变更 observer.observe(observeElem, { childList: true, subtree: true, attributes: true }); }); } - 第二步:改造原有的遍历函数为async异步函数,在else分支等待MutationObserver回调
把grab_data改为async函数,在else分支点击按钮后,await上面封装的Promise,等待数据就绪后再继续循环。
修改后的完整代码示例:async function grab_data() { // 从DOM中获取存储转录历史的父元素 var parent_elem = document.querySelector("#yDmH0d > c-wiz > div > div.jkOv3d > c-wiz:nth-child(4) > c-wiz > c-wiz > div > div:nth-child(1)"); for (let i = 0; i < (parent_elem.children.length); i++) { if (parent_elem.children[i].hasAttribute("data-timestamp")) { // 常规场景,正常处理数据 some_code(); } else { // 特殊场景,先点击按钮触发DOM变更 example_button.click(); // 等待MutationObserver监听到预期的变更,校验逻辑根据实际业务调整 await waitForTargetMutation(parent_elem, (mutations) => { // 这里写你的校验规则:比如判断当前位置的元素已经生成了data-timestamp属性、或者对应数据已加载完成 return parent_elem.children[i].hasAttribute("data-timestamp"); }); // 等待结束后自动进入下一轮循环 } } }
注意事项
- 每次监听到符合预期的变更后必须调用
disconnect()销毁MutationObserver实例,避免累积大量无效监听导致内存泄漏 - 如果担心页面异常导致监听卡住,可以给Promise加超时逻辑,比如用
Promise.race([waitForTargetMutation(), new Promise((_,rej) => setTimeout(()=>rej('加载超时'),3000))])处理超时场景 - 建议优先使用更通用的选择器定位父元素,避免页面结构动态变化后原选择器失效,导致获取不到元素报错
内容的提问来源于stack exchange,提问作者Emilie
相关产品推荐
相关产品推荐

