大数据表格如何渲染

大数据表格如何渲染?

维格表、飞书表格、钉钉表格,在线表格追求大数据量

1.数据足够大,大数据公司,需要在前端展示大量数据,以往防卡顿,所以我们想要通过更好方案实现。
2.我作为负责人,调研这部分方案
1.dom
2.虚拟表格
3.canvas table
4.可视区绘制算法优化
5.canvas 结合 Webassembly 技术实现(skia + Webassembly)
3.我封装了画布表格引擎,解决了上述问题,并且能够实现 1000w 数据加载流畅交互
4.在这个过程中遇到那些问题,我是怎么解决问题的,卡点

虚拟表格

  1. 虚拟表格的基本原理
    虚拟表格的核心思想是只渲染用户当前可见的部分数据,而不是一次性渲染整个数据集。通过这种方式,可以显著减少DOM节点的数量,从而提高渲染性能和用户交互的流畅性。
  2. 实现步骤
    数据分片:将大数据集分成多个小块,只在用户滚动时加载当前可见区域的数据。
    计算可见区域:根据用户的滚动位置,计算出当前可见的行数和列数。
    动态渲染:根据可见区域的数据动态渲染表格,只在DOM中插入当前可见的数据行。
    占位符:为了保持表格的整体布局,可以使用占位符来填充未渲染的行,确保表格的高度和宽度保持一致。
  3. 第三方的插件虚拟表格插件
    vxe-table
    代码
<template>
  <div>
    <vxe-table
      :data="tableData"
      :scroll-y="{ enabled: true }"
      :scroll-x="{ enabled: true }"
      :height="tableHeight"
      :max-height="maxHeight"
      :column-config="{ resizable: true }"
      :size="'medium'"
      stripe
      border
      :virtual-scroll="{ enabled: true }"
    >
      <vxe-column field="id" title="ID" width="100"></vxe-column>
      <vxe-column field="name" title="Name" width="200"></vxe-column>
      <vxe-column field="age" title="Age" width="100"></vxe-column>
      <!-- 其他列 -->
    </vxe-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tableData: [], // 用于存储大数据
      tableHeight: 600, // 表格高度
      maxHeight: 800, // 最大高度
    };
  },
  created() {
    this.loadData();
  },
  methods: {
    loadData() {
      // 模拟加载大数据
      const data = [];
      for (let i = 0; i < 1000000; i++) {
        data.push({
          id: i,
          name: `Name ${i}`,
          age: Math.floor(Math.random() * 100),
        });
      }
      this.tableData = data;
    },
  },
};
</script>

<style>
/* 你可以在这里添加自定义样式 */
</style>

canvas table

  1. 基本原理
    Canvas 是一种图形绘制技术,可以直接在网页上绘制图形和文本。通过使用 Canvas,我们可以在一个画布上绘制表格的可见部分,而不是在 DOM 中创建大量的元素。这种方式可以显著提高渲染性能。

  2. 代码

<template>
  <div>
    <canvas id="dataTableCanvas" width="800" height="600"></canvas>
  </div>
</template>

<script>
export default {
  data() {
    return {
      canvas: null,
      ctx: null,
      tableData: [], // 存储大数据
      rowHeight: 30, // 每行高度
      visibleRows: 20, // 可见行数
      scrollTop: 0, // 当前滚动位置
    };
  },
  mounted() {
    this.canvas = document.getElementById('dataTableCanvas');
    this.ctx = this.canvas.getContext('2d');
    this.loadData();
    this.drawTable();
    this.canvas.addEventListener('scroll', this.onScroll);
  },
  methods: {
    loadData() {
      // 模拟加载大数据
      const data = [];
      for (let i = 0; i < 1000000; i++) {
        data.push({
          id: i,
          name: `Name ${i}`,
          age: Math.floor(Math.random() * 100),
        });
      }
      this.tableData = data;
    },
    drawTable() {
      const startRow = Math.floor(this.scrollTop / this.rowHeight);
      const endRow = startRow + this.visibleRows;

      // 清空画布
      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

      // 绘制表头
      this.ctx.fillStyle = '#f0f0f0';
      this.ctx.fillRect(0, 0, this.canvas.width, this.rowHeight);
      this.ctx.fillStyle = '#000';
      this.ctx.fillText('ID', 10, 20);
      this.ctx.fillText('Name', 100, 20);
      this.ctx.fillText('Age', 300, 20);

      // 绘制数据行
      for (let i = startRow; i < endRow && i < this.tableData.length; i++) {
        const row = this.tableData[i];
        this.ctx.fillStyle = '#fff';
        this.ctx.fillRect(0, (i - startRow + 1) * this.rowHeight, this.canvas.width, this.rowHeight);
        this.ctx.fillStyle = '#000';
        this.ctx.fillText(row.id, 10, (i - startRow + 1) * this.rowHeight + 20);
        this.ctx.fillText(row.name, 100, (i - startRow + 1) * this.rowHeight + 20);
        this.ctx.fillText(row.age, 300, (i - startRow + 1) * this.rowHeight + 20);
      }
    },
    onScroll(event) {
      this.scrollTop = event.target.scrollTop;
      this.drawTable();
    },
  },
};
</script>

<style>
/* 你可以在这里添加自定义样式 */
</style>
  1. 关键点说明
    Canvas 绘制:使用 fillRect 和 fillText 方法在 Canvas 上绘制表格的行和列。
    滚动处理:通过监听 Canvas 的滚动事件,更新 scrollTop 并重新绘制可见区域的表格。
    性能优化:由于 Canvas 只绘制可见区域,避免了大量 DOM 操作,从而提高了性能。

canvas 结合 Webassembly 技术实现(skia + Webassembly)

要实现一个结合 Canvas 和 WebAssembly 的表格渲染方案,使用 Skia Graphics Library 是一个很好的选择。Skia 是一个开源的 2D 图形库,广泛用于 Google 的产品中。通过 WebAssembly,可以将 Skia 编译为可以在浏览器中运行的代码,从而实现高性能的图形渲染。
实现步骤
以下是一个简化的实现步骤,展示如何使用 Skia 和 WebAssembly 来渲染一个表格。请注意,这个过程涉及多个步骤,包括设置开发环境、编译 Skia、编写 WebAssembly 代码等。

  1. 环境准备
    首先,你需要安装以下工具:
    Emscripten:用于将 C++ 代码编译为 WebAssembly。
    Skia:下载并构建 Skia。
    安装 Emscripten
    请参考 Emscripten 官方文档 进行安装。
    下载和构建 Skia
  2. 克隆 Skia 仓库:
   git clone https://skia.googlesource.com/skia.git
   cd skia
  1. 按照 Skia 的构建说明进行设置,确保使用 Emscripten 作为编译器。

  2. 编写 C++ 代码
    创建一个 C++ 文件,例如 table_renderer.cpp,用于渲染表格。

#include "include/core/SkCanvas.h"
#include "include/core/SkPaint.h"
#include "include/core/SkStream.h"
#include "include/core/SkSurface.h"
#include "include/core/SkImage.h"
#include "include/core/SkFont.h"
#include "include/core/SkTypeface.h"

extern "C" {
    void render_table(SkCanvas* canvas) {
        SkPaint paint;
        paint.setColor(SK_ColorWHITE);
        canvas->drawRect(SkRect::MakeWH(800, 600), paint); // 背景

        // 绘制表头
        paint.setColor(SK_ColorGRAY);
        canvas->drawRect(SkRect::MakeXYWH(0, 0, 800, 30), paint);
        paint.setColor(SK_ColorBLACK);
        paint.setTextSize(20);
        canvas->drawString("ID", 10, 20, paint);
        canvas->drawString("Name", 100, 20, paint);
        canvas->drawString("Age", 300, 20, paint);

        // 绘制数据行
        for (int i = 0; i < 100; i++) {
            paint.setColor(i % 2 == 0 ? SK_ColorWHITE : SK_ColorLTGRAY);
            canvas->drawRect(SkRect::MakeXYWH(0, (i + 1) * 30, 800, 30), paint);
            paint.setColor(SK_ColorBLACK);
            canvas->drawString(std::to_string(i).c_str(), 10, (i + 1) * 30 + 20, paint);
            canvas->drawString(("Name " + std::to_string(i)).c_str(), 100, (i + 1) * 30 + 20, paint);
            canvas->drawString(std::to_string(rand() % 100).c_str(), 300, (i + 1) * 30 + 20, paint);
        }
    }
}
  1. 编译 C++ 代码为 WebAssembly
    使用 Emscripten 编译 C++ 代码为 WebAssembly:
emcc table_renderer.cpp -o table_renderer.js -s WASM=1 -s EXPORTED_FUNCTIONS='["_render_table"]' -I/path/to/skia/include -L/path/to/skia/out/ -lskia
  1. 创建 HTML 文件
    创建一个 HTML 文件 index.html,用于加载 WebAssembly 模块并渲染表格。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Skia + WebAssembly Table</title>
    <script src="table_renderer.js"></script>
</head>
<body>
    <canvas id="canvas" width="800" height="600"></canvas>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');

        // 等待 WebAssembly 加载
        Module.onRuntimeInitialized = () => {
            const skiaCanvas = new SkCanvas(ctx); // 假设有 SkCanvas 类
            Module._render_table(skiaCanvas); // 调用 C++ 渲染函数
        };
    </script>
</body>
</html>
  1. 运行项目
  2. 使用一个本地服务器(如 http-server 或 live-server)来运行项目。
  3. 打开浏览器,访问相应的 URL,你应该能够看到使用 Skia 和 WebAssembly 渲染的表格。

WebAssembly与用canvas table 实现大数据表格的区别

  1. 性能
    WebAssembly:
    WebAssembly(Wasm)是一种低级字节码格式,旨在提供接近原生性能的执行速度。它允许开发者使用 C/C++ 等语言编写高性能的代码,并在浏览器中运行。
    使用 WebAssembly 和图形库(如 Skia)可以实现高效的图形渲染,适合需要复杂计算和高性能渲染的场景。

Canvas Table:
使用 Canvas API 直接在 JavaScript 中绘制图形和文本,性能相对较低,尤其是在处理大量 DOM 操作时。
对于简单的表格渲染,Canvas 可以提供足够的性能,但在处理复杂的图形或大量数据时,可能会出现性能瓶颈。

  1. 开发复杂性
    WebAssembly:
    开发过程相对复杂,需要设置编译工具链(如 Emscripten),并编写 C/C++ 代码。
    需要处理与 JavaScript 的交互,可能涉及更多的学习曲线。

Canvas Table:
使用 JavaScript 和 HTML5 Canvas API,开发相对简单,易于上手。
适合快速原型开发和简单的表格展示。

  1. 适用场景
    WebAssembly:
    适合需要高性能计算和复杂图形渲染的应用,如游戏、图形编辑器、数据可视化等。
    当需要处理大量数据并进行复杂计算时,WebAssembly 可以显著提高性能。

Canvas Table:
适合简单的表格展示和交互,尤其是在数据量不大的情况下。
对于需要快速开发和简单实现的场景,Canvas 是一个不错的选择。

  1. 生态系统和工具支持
    WebAssembly:
    生态系统相对较新,虽然有许多库和工具支持,但仍在不断发展中。
    需要依赖于其他图形库(如 Skia)来实现复杂的图形渲染。

Canvas Table:
有丰富的文档和社区支持,许多现成的库和框架(如 vxe-table、ag-Grid 等)可以帮助快速实现表格功能。
直接使用 JavaScript 和 HTML,易于集成和使用。

总结
WebAssembly 提供了更高的性能和更复杂的图形处理能力,适合需要高效渲染和计算的应用场景,但开发复杂性较高。
Canvas Table 更加简单易用,适合快速开发和简单的表格展示,但在处理大量数据时性能可能不足。
支持
WebAssembly:
生态系统相对较新,虽然有许多库和工具支持,但仍在不断发展中。
需要依赖于其他图形库(如 Skia)来实现复杂的图形渲染。

Canvas Table:
有丰富的文档和社区支持,许多现成的库和框架(如 vxe-table、ag-Grid 等)可以帮助快速实现表格功能。
直接使用 JavaScript 和 HTML,易于集成和使用。

总结
WebAssembly 提供了更高的性能和更复杂的图形处理能力,适合需要高效渲染和计算的应用场景,但开发复杂性较高。
Canvas Table 更加简单易用,适合快速开发和简单的表格展示,但在处理大量数据时性能可能不足。
选择哪种技术取决于具体的应用需求、性能要求和开发团队的技术栈。

### Ant Design 表格组件在处理大数据时的优化方法 #### 数据分页加载 对于大型数据集,一次性渲染全部数据会显著影响性能。采用分页机制可以有效减少每次请求的数据量,从而提高页面响应速度和用户体验[^1]。 ```javascript const [dataSource, setDataSource] = useState([]); const [pagination, setPagination] = useState({ current: 1, pageSize: 10, }); useEffect(() => { fetch(`https://api.example.com/data?page=${pagination.current}&size=${pagination.pageSize}`) .then(response => response.json()) .then(data => setDataSource(data.items)); }, [pagination]); return ( <Table dataSource={dataSource} pagination={{ ...pagination, onChange(page) { setPagination({ ...pagination, current: page }); }, }} /> ); ``` #### 虚拟滚动条(Virtualized Scroll) 当表格行数非常多时,虚拟列表技术只渲染可见区域内的DOM节点,极大地减少了浏览器需要处理的元素数量,提升了整体效率[^3]。 ```javascript import InfiniteScroll from 'react-infinite-scroll-component'; <InfiniteScroll dataLength={items.length} next={() => loadMore()} hasMore={true} > <Table scroll={{ y: 400 }} // 设置固定高度并启用纵向滚动 loading={loading} rowKey="id" columns={columns} dataSource={visibleItems} /> </InfiniteScroll> ``` #### 延迟加载列定义 如果某些复杂计算仅用于特定视图,则可以在实际需要之前延迟这些操作直到用户交互触发它们为止。这有助于降低初始加载时间,并使界面更加流畅[^2]。 ```javascript function getColumns() { const baseColumns = [ { title: 'Name', dataIndex: 'name' }, { title: 'Age', dataIndex: 'age' } ]; if (showExtraInfo) { return [...baseColumns, { title: 'Address', dataIndex: 'address' }]; } return baseColumns; } // Only compute extra column when necessary const columns = useMemo(getColumns, [showExtraInfo]); ``` #### 减少不必要的重绘 通过合理设置`key`属性来帮助React识别哪些元素发生了变化;利用`shouldComponentUpdate()`生命周期函数阻止不必要更新;或者借助于更高级别的抽象如`React.memo()`或`PureComponent`类实现浅比较优化[^4]。 ```javascript class OptimizedTableRow extends PureComponent { shouldComponentUpdate(nextProps) { return !isEqual(this.props.record, nextProps.record); // Use lodash's isEqual method to compare objects deeply. } render() { const { record } = this.props; return ( <tr key={record.id}> {/* Render table cells */} </tr> ); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值