多款表格性能对比

1,764 阅读3分钟

前言

在上一篇《在线电子表格分析调研》中,我们提到了多款在线电子表格,以及阿里内部对电子表格的一些使用情况。本篇文章我们将对钉钉表格、fusion里面的表格组件及另外一款ali-react-table插件,这三款表格做进一步的性能对比。而之前提到的羽雀表格由于没有开源,我们就暂时不比较了。 ​

性能分析工具

本文用到的性能分析工具主要是react 自身提供的 Profiler,这里我们并没有手动调用API,而是直接安装了 React Developer Tools(谷歌插件市场:chrome://extensions/) 谷歌插件就可以使用了。更多介绍可以参考《React 官方发布性能分析插件Profiler》文章 ​

钉钉表格

示例代码

import SmartTable from '@ali/smart-table';
import { components } from '@ali/smart-table-components';
import React from 'react';

const refSheet = React.createRef();


const getFields = ((cols) => { // 生成列数据
  let arr = []
  for (let i = 0; i < cols; i++) {
    arr.push({ "id": `${i}_$`, "name": `第${i}列`, "dataType": "text" })
  }
  return arr;
})(200)

const getRows = ((rows, cols) => { // 生成行数据
  let arr = []
  for (let i = 0; i < rows; i++) {
    let field = {}
    for (let j = 0; j < cols; j++) {
      field[`${j}_$`] = `第${j}列第${i+1}行`;
    }
    arr.push({ id: i, ...field })
  }
  return arr;
})(2000, 200)

export default class DingTable extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      defaultValue: {
        id: 'students',
        showIndexField: true,
        sheets: [{
          "name": "名单",
          "fields": getFields,
          "rows": getRows,
        }],
        
        allowSelector: false,
        allowSort: true,
        allowFilter: true,
        allowGroup: true,
        allowAggregate: true,
        allowEditCell: false,
        allowRenameField: true,
        allowDeleteField: true,
        allowChangeFieldDataType: true,
        allowMoveField: true,
        allowResizeField: true,
        allowInsertField: true,
        allowInsertRow: true,
        allowDeleteRow: true,
        allowSelectRow: true,
        showHeaderCellMenu: true,
        showSummaryBar: true,
      },
    }
  }
  
  render () {
    return <SmartTable
      ref={refSheet}
      defaultValue={this.state.defaultValue}
      components={components}
      shouldSetCell={async (values) => {
        return true;
      }}
      style={{
        width: '100vw',
        height: '500px',
      }}
    />
  }
  
}

运行截图

fusion表格

示例代码(官网地址:fusion.design/pc/?themeid…

import Table from '@alifd/next/lib/table';
import '@alifd/next/dist/next.min.css';
import React from 'react';

const getFields = ((cols) => { // 生成列
  let arr = []
  for (let i = 0; i < cols; i++) {
    arr.push({ "id": `${i}_$`, "name": `第${i}列`, "dataType": "text" })
  }
  return arr;
})(30)

const getDataSource = ((rows, cols) => { // 生成行
  let arr = []
  for (let i = 0; i < rows; i++) {
    let field = {}
    for (let j = 0; j < cols; j++) {
      field[`${j}_$`] = `第${j}列第${i+1}行`;
    }
    arr.push({ id: i, ...field })
  }
  return arr;
})(10000, 30)


export default class NextTable extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      dataSource: getDataSource,
      columnData: getFields,
    }
  }
  
  render () {
    return <Table dataSource={this.state.dataSource} useVirtual maxBodyHeight={500}>
      {
        this.state.columnData.map((column, index) => {
          return <Table.Column width={100} title={column.name} dataIndex={`${index}_$`} />
        })
      }
    </Table>
  }
}

运行截图

ali-react-table

示例代码(github地址:github.com/alibaba/ali…

import { BaseTable } from 'ali-react-table'
import React from 'react'

const getFields = ((cols) => { // 生成列
  let arr = []
  for (let i = 0; i < cols; i++) {
    arr.push({ code: `${i}_$`, "name": `第${i}列`, width: 100 })
  }
  return arr;
})(30)

const getDataSource = ((rows, cols) => { // 生成行
  let arr = []
  for (let i = 0; i < rows; i++) {
    let field = {}
    for (let j = 0; j < cols; j++) {
      field[`${j}_$`] = `第${j}列第${i+1}行`;
    }
    arr.push({ id: i, ...field })
  }
  return arr;
})(10000, 30)

export default class AliReactTable extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      dataSource: getDataSource,
      columnData: getFields,
    }
  }
  
  render () {
    return <BaseTable dataSource={this.state.dataSource} useVirtual columns={this.state.columnData} />
  }
}

运行截图

数据对比情况

****钉钉(渲染耗时:ms)ali-react-table(渲染耗时:ms)fusion(渲染耗时:ms)
1000行/20列673062
5000行/100列14728131
10000行/200列39230172
20000行/300列127332292
30000行/500列未测出31414
卡顿情况(满分5分)4分5分5分
快速滚动白屏明显不太明显明显

总结

  1. 三款表格都通过使用虚拟滚动的方式(即仅渲染屏幕内的dom节点)来加载大批量数据,不同点在于fusion表格仅支持纵向虚拟滚动,不支持横向虚拟滚动,而其他2款均支持。
  2. 从渲染耗时来看,虽然钉钉表格相对于其他两款耗时更长,流畅性也差一点。但是钉钉表格默认的基础配置里是支持排序、过滤、多选、增删改等操作的,无需引入额外的代码,只需配置是否开启即可。而其他两款表格仅是基础的数据展示功能,若同样配置以上功能,性能不一定会高于钉钉,这一点还需进一步验证。
  3. 由于ali-react-table支持了横向虚拟滚动,所以不管数据量大小渲染耗时基本都在 30ms 左右;而fusion表格随着列数的增多,耗时也会相应增加。
  4. 三款表格都出现了纵向快速滚动,页面白屏的情况。但相较于其他两款表格,ali-react-table的表现会好一点儿,不会出现满屏白屏,仅是浏览器底部位置部分白屏。这一点ali-react-table应该是做了优化处理。