Leon's blog Leon's blog
首页
前端
场景
技术
更多
关于
收藏
索引
GitHub (opens new window)

Leon Yu

做一个有个性的开发者~
首页
前端
场景
技术
更多
关于
收藏
索引
GitHub (opens new window)
  • 场景
  • ResizeObserver防抖优化性能
    • useAbortableRequest
    • requestAnimation与滚动
    • 支持promise的并发
    • 单点登录场景与理解
    • 前端路由
    • 场景
    leon yu
    2024-06-15
    目录

    ResizeObserver防抖优化性能

    提示

    在工作中,有遇到过与页面回流相关的性能优化问题

    # 明确定义

    • 回流(Reflow):又称为布局,是浏览器为了重新计算页面中元素的位置和大小而进行的过程。当DOM的变化影响到元素的几何信息(如宽度、高度、边距等)时,浏览器需要重新计算元素的位置和大小,然后再进行渲染。这个过程是计算密集型的,可能会导致页面的性能问题。

    • 重绘(Repaint):当元素的外观(颜色、背景等)发生变化,但几何属性未变时,浏览器将进行重绘。重绘不涉及元素位置的改变,因此成本较回流为低。

    # 工作场景再现

    项目的背景是一个数据可视化平台,左侧有一个折叠面板,可以伸缩,从展开到折叠的过程中会有动画,右侧为页面的主体,有大量的 echarts 图表。

    正如之前所言,折叠面板的折叠与展开过程涉及到动画,动画过程中折叠面板的宽度不断变化,导致页面会发生不断的回流,而在这个过程中,echarts 图表也会进行同步的收缩。

    这当然是一个好特性,但是这个计算密集型的过程也造成了浏览器的较大压力,会导致页面卡顿,影响了首页的使用体验。

    # 检测回流次数的方法

    在每一个组件内部,加入一个副作用,当检测到父容器尺寸变化时,echarts 就会进行伸缩,在这个时候,在控制台打印一次尺寸变化提醒消息。

    经过检测,折叠面板折叠和展开的过程中,共发生了800+次的 echarts 图表尺寸调整,对性能造成了巨大的压力。

    加入防抖后,重新检测,发现这个数字变成了100,页面的整体流畅度得到了极大的提高。

    # 代码封装

    注意

    代码仅为示例,实际代码要与业务相结合,以下代码为ai生成,不一定可以运行。

    // debounce.js
    export default function debounce(func, wait) {
      let timeout;
      return function(...args) {
        const context = this;
        clearTimeout(timeout);
        timeout = setTimeout(() => func.apply(context, args), wait);
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    import React, { useState, useEffect, useRef } from 'react';
    import * as echarts from 'echarts/core';
    import { BarChart } from 'echarts/charts';
    import { CanvasRenderer } from 'echarts/renderers';
    import { GridComponent, TooltipComponent } from 'echarts/components';
    import debounce from './debounce.js'
    
    echarts.use([BarChart, CanvasRenderer, GridComponent, TooltipComponent]);
    
    const option = {
      tooltip: {},
      xAxis: {
        data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
      },
      yAxis: {},
      series: [
        {
          name: '销量',
          type: 'bar',
          data: [5, 20, 36, 10, 10, 20]
        }
      ]
    };
    
    const EChartsComponent = () => {
      const chartRef = useRef(null);
      const [chart, setChart] = useState(null);
    
      // 初始化图表
      useEffect(() => {
        if (chartRef.current && !chart) {
          const myChart = echarts.init(chartRef.current);
          setChart(myChart);
        }
      }, [chart]);
    
      // 防抖调整图表尺寸
      const resizeChart = debounce(() => {
        chart && chart.resize();
      }, 300);
    
      // 使用ResizeObserver监听容器尺寸变化
      useEffect(() => {
        if (chartRef.current) {
          const resizeObserver = new ResizeObserver(resizeChart);
          resizeObserver.observe(chartRef.current);
    
          return () => {
            resizeObserver.disconnect();
          };
        }
      }, [chart]);
    
      // 设置图表配置项
      useEffect(() => {
        if (chart) {
          chart.setOption(option);
        }
      }, [chart]);
    
      return <div ref={chartRef} style={{ width: '600px', height: '400px' }}></div>;
    };
    
    export default EChartsComponent;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    最近更新~: 2024/08/19, 01:05:55
    场景
    useAbortableRequest

    ← 场景 useAbortableRequest→

    最近更新
    01
    应用层
    01-11
    02
    计算机网络和因特网
    12-22
    03
    关于
    12-22
    更多文章>
    Theme by Vdoing | Copyright © 2024-2025 主题来自 Evan Xu | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式