控制台报错啦!!!之 超时警告

setInterval 超时警告

控制台报错啦!!!之  超时警告

出现报错:

[Violation] 'setInterval' handler took 71ms

意味着: ‘setInterval’ 处理程序耗时 71 毫秒

当然这只是一个小小的警告如果解决不了也不会影响项目的运行,

解决这个问题最好的办法就是关闭控台,hhhh,

眼不见心不烦,解决不了问题,就解决报问题的地方🤣

当然我们还是要来看一看这到底是何方神圣的。

定位问题

首先根据警告的信息提示,定位问题

控制台报错啦!!!之  超时警告

浏览器将报错定位在设置地图轮播的定时器上

当前项目所在的位置是一个大屏项目,在大屏展示中用到了 echarts 的各种组件其中包括地图及其散点图轮播功能的实现。

初步猜测这个报错提示可能是因为轮播过程中 setInterval 函数执行时间过长,超过了浏览器设定的最大时间限制。当然这个限制是为了防止 JavaScript 运行时间过长导致页面卡死。

那么先来看一看地图效果是怎么实现的吧:

echarts 散点轮播的实现

  1. 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>
  1. 设置散点的轮播效果

通过 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 的可能。

参考

  1. 一文搞定echarts地图轮播高亮

原文链接:https://juejin.cn/post/7231097076062093372 作者:雅伊

(0)
上一篇 2023年5月9日 上午10:21
下一篇 2023年5月10日 上午10:05

相关推荐

发表评论

登录后才能评论