Report报告开发实战从零到一的那些坑与核心技术分享

诸葛曦月 工具 阅读 1,488
赞 69 收藏
二维码
手机扫码查看
反馈

优化前:卡得不行

最近在做一个报表项目,性能问题让我头疼了好一阵子。这个报表页面加载速度慢得让人抓狂,特别是数据量大的时候,简直卡得受不了。用户反馈说打开报表页面要等好几秒,体验非常糟糕。

Report报告开发实战从零到一的那些坑与核心技术分享

找到瘼颈了!

首先,我得搞清楚到底是哪里出了问题。我用了一些工具来定位问题,比如Chrome的开发者工具和Lighthouse。通过这些工具,我发现以下几个主要问题:

  • 大量的DOM操作导致重绘和回流
  • 大量未优化的JavaScript代码
  • 图片资源过大且未压缩

其中最严重的问题是DOM操作过多。每次数据更新时,整个表格都会重新渲染,这导致了大量的重绘和回流,严重影响了性能。

优化方法一:虚拟滚动

第一个优化方案是引入虚拟滚动。虚拟滚动可以减少DOM元素的数量,只渲染当前可见的部分,从而提高性能。我试了几种方案,最后发现使用react-virtualized库效果最好。

优化前的代码大概是这样的:

import React from 'react';

class Table extends React.Component {
  render() {
    const { data } = this.props;
    return (
      <table>
        <thead>
          <tr>
            <th>列1</th>
            <th>列2</th>
            <th>列3</th>
          </tr>
        </thead>
        <tbody>
          {data.map((row, index) => (
            <tr key={index}>
              <td>{row.column1}</td>
              <td>{row.column2}</td>
              <td>{row.column3}</td>
            </tr>
          ))}
        </tbody>
      </table>
    );
  }
}

优化后的代码使用了react-virtualized

import React from 'react';
import { Table, Column, Cell } from 'react-virtualized';

class VirtualizedTable extends React.Component {
  renderCell = ({ cellData, columnData }) => {
    return cellData;
  };

  render() {
    const { data } = this.props;
    return (
      <Table
        width={800}
        height={400}
        headerHeight={40}
        rowHeight={40}
        rowCount={data.length}
        rowGetter={({ index }) => data[index]}
      >
        <Column
          label="列1"
          dataKey="column1"
          width={200}
          cellRenderer={this.renderCell}
        />
        <Column
          label="列2"
          dataKey="column2"
          width={200}
          cellRenderer={this.renderCell}
        />
        <Column
          label="列3"
          dataKey="column3"
          width={200}
          cellRenderer={this.renderCell}
        />
      </Table>
    );
  }
}

引入虚拟滚动后,表格的加载时间从5秒降到了800毫秒,效果非常明显。

优化方法二:代码优化

接下来是对JavaScript代码进行优化。我发现有些地方的代码重复计算了很多次,还有一些不必要的DOM操作。我用了React.memouseMemo来缓存一些计算结果,减少了不必要的渲染。

优化前的代码大概长这样:

import React, { useState, useEffect } from 'react';

const Report = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    fetchData();
  }, []);

  const fetchData = async () => {
    const response = await fetch('https://jztheme.com/api/data');
    const result = await response.json();
    setData(result);
  };

  const calculateTotal = (data) => {
    let total = 0;
    for (let i = 0; i < data.length; i++) {
      total += data[i].value;
    }
    return total;
  };

  return (
    <div>
      <h1>报表</h1>
      <p>总数: {calculateTotal(data)}</p>
      <table>
        <thead>
          <tr>
            <th>列1</th>
            <th>列2</th>
            <th>列3</th>
          </tr>
        </thead>
        <tbody>
          {data.map((row, index) => (
            <tr key={index}>
              <td>{row.column1}</td>
              <td>{row.column2}</td>
              <td>{row.column3}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

优化后的代码如下:

import React, { useState, useEffect, useMemo } from 'react';

const Report = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    fetchData();
  }, []);

  const fetchData = async () => {
    const response = await fetch('https://jztheme.com/api/data');
    const result = await response.json();
    setData(result);
  };

  const calculateTotal = (data) => {
    let total = 0;
    for (let i = 0; i < data.length; i++) {
      total += data[i].value;
    }
    return total;
  };

  const total = useMemo(() => calculateTotal(data), [data]);

  return (
    <div>
      <h1>报表</h1>
      <p>总数: {total}</p>
      <table>
        <thead>
          <tr>
            <th>列1</th>
            <th>列2</th>
            <th>列3</th>
          </tr>
        </thead>
        <tbody>
          {data.map((row, index) => (
            <tr key={index}>
              <td>{row.column1}</td>
              <td>{row.column2}</td>
              <td>{row.column3}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

通过使用useMemo,计算总数的操作只在数据变化时执行一次,避免了每次渲染都重新计算,性能有了显著提升。

优化方法三:图片优化

最后一个优化点是图片资源。我发现很多图片都没有经过压缩,体积非常大。我用了一些在线工具(如TinyPNG)来压缩图片,并将图片转换为WebP格式。这样不仅减小了图片的体积,还提高了加载速度。

优化前的HTML代码:

<img src="https://jztheme.com/images/report.png" alt="Report Image">

优化后的HTML代码:

<img src="https://jztheme.com/images/report.webp" alt="Report Image">

通过这些优化,页面的整体加载时间从原来的5秒缩短到了1秒左右,用户体验得到了极大的提升。

优化后:流畅多了

经过这几轮优化,报表页面的性能问题终于得到了解决。用户反馈说现在打开报表页面快了很多,不再有那种卡顿的感觉。虽然还有些小问题需要继续优化,但总体来说已经达到了预期的效果。

以上是我的优化经验,如果大家有更好的方案或者遇到类似的问题,欢迎在评论区交流。希望这篇文章能对你们有所帮助。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论