MutationObserver无法检测querySelectorAll返回元素的内容变化该如何解决
问题原因
- 原代码未判断目标
code元素(索引为10的节点)是否存在就直接读取属性,页面跳转后目标元素可能还未渲染完成,直接访问code[10]会抛出异常,导致后续逻辑终止 - 全文档监听的回调触发频率极高,很容易在目标内容还未完成更新时就提前读取,拿到旧的内容
- 未做重复内容过滤与防抖处理,相同内容重复触发解析逻辑,既浪费性能也容易出现异常
调整后的代码
// 存储上一次读取到的有效内容,避免重复处理 let lastContent = '' // 防抖定时器,避免频繁触发逻辑 let timer: number | null = null const observer = new MutationObserver(() => { // 清除上一次的未执行定时器,实现防抖效果 if (timer) clearTimeout(timer) timer = window.setTimeout(() => { const codeList = document.querySelectorAll('code') // 先判断目标元素是否存在,避免下标越界报错 if (codeList.length < 11) return const currentContent = codeList[10].textContent?.trim() // 内容为空或者和上一次内容一致时直接跳过 if (!currentContent || currentContent === lastContent) return try { const parser = JSON.parse(currentContent) const getData = parser.elements console.log(getData) // 更新存储的上一次内容 lastContent = currentContent } catch (err) { // 捕获JSON解析异常,避免内容格式错误导致代码中断 console.warn('JSON解析失败', err) } }, 300) // 防抖时长可根据页面实际加载速度调整 }) observer.observe(document, { attributes: true, characterData: true, childList: true, subtree: true, attributeOldValue: true, characterDataOldValue: true, }) // 页面卸载时断开监听,避免内存泄漏 window.addEventListener('beforeunload', () => { observer.disconnect() if (timer) clearTimeout(timer) })
优化说明
- 新增目标元素存在性判断,只有页面中存在至少11个
code元素时才会执行后续逻辑,避免下标越界报错 - 加入300ms防抖逻辑,等页面DOM更新完成后再读取内容,避免拿到未更新完成的旧内容
- 存储上一次的有效内容,只有内容发生变化时才会执行解析逻辑,减少不必要的性能损耗
- 新增JSON解析异常捕获,避免内容格式不对时导致整段代码崩溃
- 新增页面卸载时的监听断开逻辑,避免内存泄漏
- 如果可以确定目标
code元素的固定父容器,建议将observe的监听对象从document改为对应的父容器节点,同时可以关闭不需要的监听项,进一步降低性能损耗
内容的提问来源于stack exchange,提问作者user16691768
相关产品推荐
相关产品推荐

