使用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目录

相关推荐
恋猫de小郭1 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅9 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端