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

相关推荐
学不会•2 小时前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
活宝小娜4 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点4 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow4 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o4 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
开心工作室_kaic5 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā5 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
沉默璇年6 小时前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder7 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
2401_882727577 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架