公司内部搭建了前端监控系统Sentry,我把一些项目接入进去,一周后发现上报数量最多的事件是ResizeObserver loop limit exceeded。这些事件上报得太多,给Sentry服务造成很大压力,于是研究一番准备解决之。
/* istanbul ignore next */
export const addResizeListener = function(element, fn) {
if (isServer) return;
if (!element.__resizeListeners__) {
element.__resizeListeners__ = [];
element.__ro__ = new ResizeObserver(resizeHandler);
element.__ro__.observe(element);
}
element.__resizeListeners__.push(fn);
};
ResizeObserver loop limit exceeded
。阻止table的重绘,例如给所有列都增加width,但是这个方案不好,无法自适应宽度。
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="date" label="日期" width="180"> </el-table-column>
<el-table-column prop="name" label="姓名" width="180"> </el-table-column>
<el-table-column prop="address" label="地址" width="180"> </el-table-column>
<el-table-column prop="address" label="地址" width="180"> </el-table-column>
<el-table-column prop="address" label="地址" width="180"> </el-table-column>
</el-table>
resize时,给回调进行节流,使其1帧内最多执行一次。代码如下:
import Vue from 'vue';
import ElementUI, { Table } from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
// 解决 ElTable 自动宽度高度导致的「ResizeObserver loop limit exceeded」问题
const fixElTableErr = (table) => {
const oldResizeListener = table.methods.resizeListener;
table.methods.resizeListener = function () {
window.requestAnimationFrame(oldResizeListener.bind(this));
};
};
// 一定要在Vue.use之前执行此函数
fixElTableErr(Table);
Vue.use(ElementUI);
new Vue({
el: '#app',
render: (h) => h(App),
});
element ui 在最新的版本中已经使用decounce方法修复了这个问题,源码如下:
/* istanbul ignore next */
export const addResizeListener = function(element, fn) {
if (isServer) return;
if (!element.__resizeListeners__) {
element.__resizeListeners__ = [];
element.__ro__ = new ResizeObserver(debounce(16, resizeHandler));
element.__ro__.observe(element);
}
element.__resizeListeners__.push(fn);
};