setInterval 超时警告
出现报错:
[Violation] 'setInterval' handler took 71ms
意味着: ‘setInterval’ 处理程序耗时 71 毫秒
当然这只是一个小小的警告如果解决不了也不会影响项目的运行,
解决这个问题最好的办法就是关闭控台,hhhh,
眼不见心不烦,解决不了问题,就解决报问题的地方🤣
当然我们还是要来看一看这到底是何方神圣的。
定位问题
首先根据警告的信息提示,定位问题
浏览器将报错定位在设置地图轮播的定时器上
当前项目所在的位置是一个大屏项目,在大屏展示中用到了 echarts 的各种组件其中包括地图及其散点图轮播功能的实现。
初步猜测这个报错提示可能是因为轮播过程中 setInterval 函数执行时间过长,超过了浏览器设定的最大时间限制。当然这个限制是为了防止 JavaScript 运行时间过长导致页面卡死。
那么先来看一看地图效果是怎么实现的吧:
echarts 散点轮播的实现
- echarts 散点图设置
首先准备一个地图,大家可以通过 DATAV.GeoAltas 阿里云提供的地图数据找到所需要的地区的信息下载对应的 json 数据即可。
这次案例中用到的是中国地图。
<script>
import * as echarts from 'echarts';
import china from './mapArea/china.json'
// 城市数据
var mapData = [
{name: '长治', value: 41},
{name: '大同', value: 58},
{name: '临汾', value: 47},
{name: '太原', value: 39},
{name: '阳泉', value: 31},
{name: '晋城', value: 70},
{name: '平遥', value: 20},
{name: '吕梁', value: 10},
];
// 城是坐标,用于散点定位
var geoCoordMap = { // 坐标
'阳泉':[113.57,37.85],
'大同':[113.3,40.12],
'长治':[113.08,36.18],
'临汾':[111.5,36.08],
'太原':[112.53,37.87],
'晋城':[112.43,36.87],
'平遥':[112.03,37.37],
'吕梁':[112.53,37.37],
}
export default {
data() {
return {
china,
timer:'',
index:-1,
option: {},
myChart:''
}
},
mounted() {
this.init()
this.mapActive()
},
beforeDestroy () {
// 消除定时器
// (注意养成良好习惯,在用到定时器的页面卸载时及时进行清除,以避免内存泄漏)
clearInterval(this.timer)
this.myChart.dispose()
},
methods: {
init() {
// 注册地图 并渲染
echarts.registerMap('china',this.china)
this.option = {
backgroundColor: '#404a59',
geo: {
map: "china",
label: {
emphasis: {
show: false
}
},
roam: false,
center:[112.38,37.67],
zoom:7,
itemStyle: {
normal: {
areaColor: "#323c48",
borderColor: "#000000"
},
emphasis: {
areaColor: "#2a333d"
}
}
},
series: [
// 散点图配置
{
name: '危险指数:',
// echarts 类型为带有涟漪特效动画的散点图
type: 'effectScatter',
coordinateSystem: 'geo',
data: [], // 暂时不设置散点数据,在后续的轮播效果中设置
symbolSize: 14,
showEffectOn: 'render',
// 涟漪效果设置
rippleEffect: {
brushType: 'stroke'
},
hoverAnimation: true,
label: {
show: true,
formatter: function(params) {
return `${ params.data.city }: ${params.data.cityData}`
},
position: 'top',
backgroundColor: 'rgba(254,174,33,.8)',
padding: [5, 10],
borderRadius: 3,
lineHeight: 32,
color: '#f7fafb',
},
itemStyle: {
color: '#f4e925',
shadowBlur: 10,
shadowColor: '#333'
},
zlevel: 1
},
]
};
this.myChart = echarts.init(document.getElementById('echartsMap'));
this.myChart.setOption( this.option);
},
},
}
</script>
- 设置散点的轮播效果
通过 setInterval 定时实现散点数据的设置
mapActive(){
if (this.timer) {
// 停止定时器,清除之前的高亮
clearInterval(this.timer)
this.timer = ''
}
// 设置定时器 轮播
this.timer = setInterval(() => {
const dataLength = mapData.length
if (this.index === dataLength - 1) {
this.index = 0
} else {
this.index++
}
// 设置当前轮播的散点高亮坐标、数据
var cityIndex = this.index
var coordCity = Object.keys(mapData)[cityIndex];
var coord = mapData[coordCity];
var geoCoord = geoCoordMap[coord.name];
this.option.series[0].data = [{
city: coord.name,
cityData: coord.value,
value: geoCoord.concat(coord.cityData)
}];
// 更新数据后重置 echarts 实例数据
this.myChart.setOption(this.option, true);
},2000);
}
至此已经实现了地图的散点轮播效果
报错解决
经过代码运行分析,该报错大概率是因为 echarts 实例在定时器内被频繁的设置导致的,
首先从以下两个方面尝试解决报错问题:
- 尝试优化定时器中的代码逻辑,使其执行时间更短,将一些计算量大或者需要频繁访问的数据缓存起来,避免重复计算或访问。
- 考虑将定时器的执行间隔调大一些,以减少定时器的触发次数。
然而在代码优化的过程中从以上两个角度来优化定时器,但是没有效果,定时器的警告问题仍然存在。
若还是无法解决那么最后一步使用浏览器的性能分析工具(如 Chrome DevTools)来分析页面性能,找出性能瓶颈所在,并进行优化。
性能分析
打开 Chrome DevTools 的 performance面板,录制当前地图轮播的过程,结束录制后能从下方生成的火焰图中当前页面存在的性能问题
从火焰图中我们能看到在散点轮播的过程中存在耗时较长的 Task(如果是耗时长的 Task,其右上角会标红),选中标红的 Task ,然后放大、选中,即可查看其具体的耗时事件及响应的消耗时长。
由此可见组件大量的重新渲染消耗了页面的性能,造成了 setInterval 的运行超时。
由于当前的 myChart 在 data 中声明,myChart数据更新时触发了数据的响应式更新,导致 echarts 实例更新的时间过长超过了定时器设定的时间。
解决方案
- 从保存 echcarts 实例变量 myChart 入手,将 myChart 从data 中移除使其失去响应式,通过echarts自身提供的 setOption 事件手动重置数据即可。
在mapActive() 块级作用域中将 myChart 设置为常量。
mapActive(){
const myChart = echarts.init(document.getElementById('echartsMap'));
myChart.setOption( this.option);
if (this.timer) {
// 停止定时器,清除之前的高亮
clearInterval(this.timer)
this.timer = ''
}
// 设置定时器 轮播
this.timer = setInterval(() => {
const dataLength = mapData.length
if (this.index === dataLength - 1) {
this.index = 0
} else {
this.index++
}
// 设置当前散点高亮坐标、数据
var cityIndex = this.index
var coordCity = Object.keys(mapData)[cityIndex];
var coord = mapData[coordCity];
var geoCoord = geoCoordMap[coord.name];
this.option.series[0].data = [{
city: coord.name,
cityData: coord.value,
value: geoCoord.concat(coord.cityData)
}];
// 重置 echarts 实例数据
myChart.setOption(this.option, true);
},2000);
}
对比修改前后 chrome 的页面性能的变化:
对 echarts 实例的存储方式进行调整后,失去了响应式的变量让页面不在频繁的重新渲染,报错也不再出现,页面的性能得到了大大提升👍
完整代码
与原先代码的区别之一:将option设置为初始数据
总结
本文记录了报错解决的全部流程:
在解决问题之前,需要重现问题并确认问题的性质和范围,依次排查问题发生的根本原因,在排查过程中尝试各种可行的解决方案,在这个过程中可以借助 Chrome DevTool 分析页面的性能问题,找到bug的根源所在。
在解决 bug 的最后一步就是及时记录解决方案和结果,积累排查问题及解决报错的经验,以便在下一次bug出现时能够及时准确的进行定位。
遇到报错不可怕,可怕的是遇到问题无从下手😭,找不到解决方案。
解决bug是一个试错的过程,尝试每一种方案,多一个解决 bug 的可能。
参考
原文链接:https://juejin.cn/post/7231097076062093372 作者:雅伊