ResizeObserver 相关问题解决方案----错误抑制
一、问题背景
在使用 ResizeObserver 监测元素尺寸变化时(尤其在 Element Plus 等 UI 组件库中),常出现以下错误:
ResizeObserver loop completed with undelivered notifications:因元素尺寸快速连续变化,浏览器无法及时处理所有尺寸变化通知,导致循环错误- 关联错误如
Cannot convert object to primitive value:可能伴随 ResizeObserver 回调执行异常出现
这些错误通常不影响功能运行,但会污染控制台输出,干扰开发调试。
二、解决方案核心思路
通过拦截错误处理机制、包装 ResizeObserver 实例,实现对特定错误的抑制,同时不影响其他正常错误的监控。
三、具体实现方案
1. 错误识别规则
定义错误过滤函数,精准匹配需要忽略的错误特征:
javascript
运行
const shouldIgnoreError = (message) => {
if (typeof message !== 'string') return false
return message.includes('ResizeObserver') ||
message.includes('loop completed with undelivered notifications') ||
message.includes('Cannot convert object to primitive value')
}
2. 重写全局错误处理
-
覆盖
window.onerror:拦截页面级错误,符合规则则阻止默认处理javascript
运行
const originalOnError = window.onerror window.onerror = function(message) { if (shouldIgnoreError(message)) return true return originalOnError ? originalOnError.apply(this, arguments) : false } -
拦截控制台输出:过滤
console.error和console.warn中的目标错误javascript
运行
const originalConsoleError = console.error console.error = function(...args) { const message = args.join(' ') if (!shouldIgnoreError(message)) { originalConsoleError.apply(console, args) } } // console.warn 处理逻辑与 error 一致,略
3. 监听错误事件
-
捕获
error事件:通过事件冒泡机制拦截错误,阻止传播javascript
运行
window.addEventListener('error', (e) => { if (shouldIgnoreError(e.message)) { e.stopImmediatePropagation() e.preventDefault() } }, true) -
处理未捕获的 Promise 异常:拦截 Promise 链中抛出的相关错误
javascript
运行
window.addEventListener('unhandledrejection', (e) => { if (e.reason && shouldIgnoreError(e.reason.message)) { e.preventDefault() e.stopPropagation() } })
4. 包装 ResizeObserver 构造函数
通过延迟执行回调避免同步循环错误:
javascript
运行
if (typeof ResizeObserver !== 'undefined') {
const originalResizeObserver = ResizeObserver
window.ResizeObserver = class extends originalResizeObserver {
constructor(callback) {
super((entries, observer) => {
// 用 setTimeout 打破同步循环,避免触发浏览器异常
setTimeout(() => {
try {
callback(entries, observer)
} catch (error) {
if (!shouldIgnoreError(error.message)) {
originalConsoleError.call(console, error)
}
}
}, 0)
})
}
}
}
四、使用方法
-
引入工具模块并执行初始化(模块加载时已自动生效核心逻辑):
javascript
运行
import { suppressResizeObserverErrors } from './resizeObserverFix.js' suppressResizeObserverErrors() // 控制台输出"ResizeObserver 错误抑制已启用" -
无需修改原有 ResizeObserver 使用方式,工具会自动拦截处理错误。
五、注意事项
- 本方案为错误抑制而非根本修复,适用于错误不影响功能的场景
- 若需彻底解决,需排查元素尺寸频繁变化的根源(如布局抖动)
- 避免过度依赖:长期应关注浏览器或组件库对 ResizeObserver 实现的优化
- 可能影响对目标错误的调试,开发阶段可暂时禁用以定位问题
六、参考代码
/**
* ResizeObserver 错误抑制工具
* 用于解决 Element Plus 等 UI 组件库中常见的 ResizeObserver 相关错误:
* - ResizeObserver loop completed with undelivered notifications
* - Cannot convert object to primitive value
* 这些错误通常不影响功能但会污染控制台,本工具通过拦截错误处理机制实现精准过滤
*/
// 保存浏览器原生的错误处理方法,用于后续需要时调用原始逻辑
const originalOnError = window.onerror; // 保存原始window.onerror错误处理函数
const originalConsoleError = console.error; // 保存原始console.error输出方法
const originalConsoleWarn = console.warn; // 保存原始console.warn输出方法
/**
* 判断错误信息是否为需要忽略的 ResizeObserver 相关错误
* @param {string} message - 错误信息字符串
* @returns {boolean} 是否需要忽略该错误
*/
const shouldIgnoreError = (message) => {
// 非字符串类型的错误信息直接返回不忽略
if (typeof message !== 'string') return false;
// 匹配 ResizeObserver 相关的特征错误信息
return message.includes('ResizeObserver') ||
message.includes('loop completed with undelivered notifications') || // 特定循环错误
message.includes('Cannot convert object to primitive value'); // 关联转换错误
};
/**
* 重写 window.onerror 全局错误处理
* 用于拦截页面级同步错误,对目标错误进行抑制
*/
window.onerror = function(message) {
// 如果是需要忽略的错误,返回true表示已处理(阻止浏览器默认报错)
if (shouldIgnoreError(message)) {
return true; // 阻止默认错误处理
}
// 非目标错误,调用原始onerror方法保持原有逻辑
if (originalOnError) {
return originalOnError.apply(this, arguments);
}
return false;
};
/**
* 重写 console.error 方法
* 用于过滤控制台输出的目标错误信息
*/
console.error = function(...args) {
// 将控制台参数拼接为字符串,便于错误识别
const message = args.join(' ');
// 如果是目标错误,不输出到控制台
if (shouldIgnoreError(message)) {
return; // 完全忽略这些错误的控制台输出
}
// 非目标错误,调用原始console.error输出
originalConsoleError.apply(console, args);
};
/**
* 重写 console.warn 方法
* 用于过滤控制台输出的目标警告信息
*/
console.warn = function(...args) {
const message = args.join(' ');
if (shouldIgnoreError(message)) {
return; // 忽略目标警告
}
originalConsoleWarn.apply(console, args);
};
/**
* 监听全局 error 事件(捕获阶段)
* 补充拦截通过事件冒泡传递的错误,确保全面性
* 第三个参数true表示在捕获阶段处理,更早拦截错误
*/
window.addEventListener('error', (e) => {
if (shouldIgnoreError(e.message)) {
e.stopImmediatePropagation(); // 阻止事件继续传播给其他监听器
e.preventDefault(); // 阻止默认处理
return false;
}
}, true);
/**
* 监听未处理的 Promise 拒绝事件
* 处理 Promise 链中未捕获的目标错误,避免控制台报错
*/
window.addEventListener('unhandledrejection', (e) => {
// 检查 Promise 拒绝原因中的错误信息
if (e.reason && shouldIgnoreError(e.reason.message)) {
e.preventDefault(); // 阻止浏览器默认处理(如控制台输出)
e.stopPropagation(); // 阻止事件传播
return false;
}
});
/**
* 包装 ResizeObserver 构造函数
* 通过延迟执行回调打破同步循环,从根源减少错误触发
*/
if (typeof ResizeObserver !== 'undefined') { // 兼容不支持ResizeObserver的环境
const originalResizeObserver = ResizeObserver; // 保存原生构造函数
// 自定义ResizeObserver类继承原生类
window.ResizeObserver = class extends originalResizeObserver {
/**
* 重写构造函数,包装回调函数
* @param {Function} callback - 尺寸变化时的回调函数
*/
constructor(callback) {
// 调用父类构造函数,传入包装后的回调
super((entries, observer) => {
// 使用setTimeout将回调延迟到下一个事件循环执行
// 目的:打破同步尺寸变化导致的循环通知,避免浏览器抛出异常
setTimeout(() => {
try {
// 执行用户传入的原始回调
callback(entries, observer);
} catch (error) {
// 回调执行中发生的错误,同样进行过滤
if (shouldIgnoreError(error.message)) {
return; // 静默忽略
}
// 非目标错误,使用原始console.error输出
originalConsoleError.call(console, error);
}
}, 0);
});
}
};
}
/**
* 工具初始化函数
* 模块加载时已自动执行核心逻辑,此函数用于标识工具已启用
*/
export const suppressResizeObserverErrors = () => {
console.log('ResizeObserver 错误抑制已启用');
};
// 默认导出工具对象
export default {
suppressResizeObserverErrors
};
通过以上方案,可有效消除 ResizeObserver 相关的冗余错误输出,提升开发体验。
1万+

被折叠的 条评论
为什么被折叠?



