使用web Worker实现前端导出大数据excel表格

需求背景:业务后台下载数据表格是调用后端接口直接下载的,但是数据量超过十万级别后,接口总是出现崩溃的情况,后端经过排查并没有找到原因,所以我就给出前端下载的方案

技术方案:由前端分页查询接口,最后汇总数据下载excel,同时由于数据量大,下载过程会比较漫长,下载过程中不能影响用户进行别的操作,所以使用 Web Worker 开启一个独立的线程进行数据的获取

我是在vue项目中调用的,可根据自己项目技术栈进行修改,好了着急改bug,我直接上代码:

首先,确定一下调用方式

js 复制代码
// 这是需要下载excel的页面.vue

// 定义表头信息
const HEAD_INFO = {
  mid: '客户ID',
  nickName: '昵称',
  livePeriod: '直播期数'
  ...
}

// 点击按钮,调用exportExcel
async exportExcel () {
  this.exportPageLoading = true
  let flowPageSize = 200

  await requestExport({
    extraParams: { ...this.$route.query, page_size: flowPageSize },
    tableHead: HEAD_INFO,
    filename: '支付流水明细',
    typeConversions: [ // 设置单元格类型
      {
        columnCode: 'N', // 第 N 列
        columnType: 'n', // 设置为 数值 类型
        headLevel: 1 // N1 是表头,不设置
      }
    ]
  })
  
  this.exportPageLoading = false
  this.$message({
    type: 'success',
    message: '***数据已成功导出,请注意查收***',
    duration: 6000
  })
},

下面就来实现requestExport方法

js 复制代码
/**
 * 下载excel
 */
export const requestExport = async ({
  extraParams,
  tableHead,
  filename,
  typeConversions
}) => {
  return new Promise((resolve, reject) => {
    let total = 0
    
    // 关于 downloadWorker 文件的路径问题,后面会说
    const worker = new Worker('./downloadWorker.js')

    let list = []
    list[0] = Object.values(tableHead)

    // 启动 worker 请求数据
    worker.postMessage({
      extraParams,
      maxLength,
      tableHead,
      cookie: document.cookie, // 接口需要鉴权,根据自己业务鉴权方式修改
    })

    worker.onmessage = (e) => {
      console.log('Web Worker 返回的数据', e.data)
      list = e.data.list
      total = e.data.total

      // 导出excel
      exportExcel(list, filename, typeConversions)

      resolve()
    }
  })
}

worker 脚本,downloadWorker.js,该文件必须放在网站根目录

js 复制代码
onmessage = async (e) => {
  console.log('web work开始执行了', e.data)

  const { extraParams, maxLength, tableHead, cookie } = e.data
  let total = 0
  let page = 1
  const pageSize = 200
  let isLastPage = false
  let list = []
  list[0] = Object.values(tableHead)

  do {
    try {
      const params = {
        page_size: pageSize,
        ...extraParams,
        page
      }

      let url = 'http://****?'

      for (const key in params) {
        if (key && params[key]) {
          if (url[url.length - 1] === '?') {
            url += `${key}=${params[key]}`
          } else {
            url += `&${key}=${params[key]}`
          }
        }
      }

      const reqHeaders = {
        Cookie: cookie
      }

      const res = await fetch(url, { headers: reqHeaders }).then(function (response) {
        return response.json()
      })

      const { data } = res

      total = data.total

      // 处理数据
      const newList = data.list.map((row) => {
        const keys = Object.keys(tableHead)
        const ret = []
        keys.forEach((key) => {
          ret.push(row[key])
        })
        return ret
      })

      list = list.concat(newList)
      page++

      if (list.length + pageSize >= total) {
        isLastPage = true
      }
    } catch (error) {
      console.log('error', error)
    }
  } while (list.length < total)

  postMessage({ list, total })
}

ok,现在功能已经实现了

注意

new Worker('./downloadWorker.js') 中的 downloadWorker.js 需要是一个网络地址,或者放在当前网站的根目录

不过public目录下的文件不会编译,如果害怕源码泄露可以在打包时编译下再copy到dist目录

相关推荐
辻戋43 分钟前
从零实现React Scheduler调度器
前端·react.js·前端框架
徐同保1 小时前
使用yarn@4.6.0装包,项目是react+vite搭建的,项目无法启动,报错:
前端·react.js·前端框架
Qrun2 小时前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp2 小时前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.3 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl5 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫6 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友6 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理8 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻8 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js