csv文件分片下载 模拟实现(简单版)

记录下csv文件分片处理下载的流程和内容

目录

记录下csv文件分片处理下载的流程和内容

1.安装mock.js和file-saver,并引入

2. 分片处理,循环存入数组,转blob,filesaver存入

3.简单版实现:

1.安装mock.js和file-saver,并引入
下载依赖:
cnpm install mockjs -S
cnpm install file-saver -S
引入依赖
import Mock from 'mockjs'
import FileSaver from 'file-saver'
2. 分片处理,循环存入数组,转blob,filesaver存入

        重要的地方在于:

        异步处理,不阻塞主线程

        分片处理,不会一次性传输数据过大,造成页面卡顿甚至崩溃

async exportCsv(total, size) {
      try {
        if (!total) throw "无数据";

        // 分片
        const step = Math.ceil(total / size);

        // CSV 缓存
        let csvArray = [];

        // 表头处理 - 一般表头由外部传入
        csvArray.push(['编号', '用户名', '官网', '报价', '创建日期'].join() + '\n');

        // 通用分片
        for (let i = 0; i < step; i++) {
          await new Promise((resolve, reject) => {
            (async () => {
              try {
                // 创建指定个数的随机数据
                const data = this.csvdata.slice(i, i + size);

                // 格式化为 CSV 字符串
                data.forEach(row => {
                  csvArray.push(Object.values(row).join() + '\n');
                });

                // 统计进度
                // const process = (i / step) * 100;
                // console.log(`进度 ${Math.round(process)}%`);

                // 适当停顿,避免页面无法执行后续
                // await new Promise((_resolve) => {
                //   setTimeout(() => _resolve(true), 50);
                // });

                resolve(true);
              } catch (error) {
                reject(error);
              }
            })();
          });
        }
        const blob = new Blob([String.fromCharCode(0xfeff), ...csvArray], {
          type: "text/plain;charset=utf-8"
        });
        await FileSaver.saveAs(blob, 'file.csv');
        return true;
      } catch (error) {
        return Promise.reject(error)
      }
    },
3.简单版实现:

实现了模拟数据的函数,100w条数据,每次数据传2000条

实际在模拟数据生成的时候会对页面造成阻塞

<template>
  <button @click="exportCsvs" :disabled="pending">导出 CSV 表格</button>
</template>

<script>
// 普通分片
import Mock from 'mockjs';
import FileSaver from 'file-saver';

export default {
  name: 'App',
  components: {

  },
  data() {
    return {
      csvdata: '',
    }
  },
  created() {
    this.getData(10000 * 100);
  },
  methods: {
    async getData(limit) {
      return new Promise((resolve, reject) => {
        try {
          const Random = Mock.Random;
          // 创建指定个数的随机数据
          const data = new Array(limit).fill('').map((_, index) => {
            return {
              id: `200820-${index}`,
              username: Random.cname(),
              url: Random.url('http'),
              price: Random.float(0, 110000, 0, 2),
              createAt: Random.datetime('yyyy-MM-dd HH:mm:ss'),
            };
          });
          this.csvdata = data
          console.log(data);
          resolve(data);
        } catch (error) {
          reject(error);
        }
      });
    },
    // 导出数据为 CSV 格式
    async exportCsv(total, size) {
      try {
        if (!total) throw "无数据";

        // 分片
        const step = Math.ceil(total / size);

        // CSV 缓存
        let csvArray = [];

        // 表头处理 - 一般表头由外部传入
        csvArray.push(['编号', '用户名', '官网', '报价', '创建日期'].join() + '\n');

        // 通用分片
        for (let i = 0; i < step; i++) {
          await new Promise((resolve, reject) => {
            (async () => {
              try {
                // 创建指定个数的随机数据
                const data = this.csvdata.slice(i, i + size);

                // 格式化为 CSV 字符串
                data.forEach(row => {
                  csvArray.push(Object.values(row).join() + '\n');
                });

                // 统计进度
                // const process = (i / step) * 100;
                // console.log(`进度 ${Math.round(process)}%`);

                // 适当停顿,避免页面无法执行后续
                // await new Promise((_resolve) => {
                //   setTimeout(() => _resolve(true), 50);
                // });

                resolve(true);
              } catch (error) {
                reject(error);
              }
            })();
          });
        }
        const blob = new Blob([String.fromCharCode(0xfeff), ...csvArray], {
          type: "text/plain;charset=utf-8"
        });
        await FileSaver.saveAs(blob, 'file.csv');
        return true;
      } catch (error) {
        return Promise.reject(error)
      }
    },
    // 创建模拟数据
    async exportCsvs() {
      try {
        this.pending = true;
        const startTime = performance.now();
        await this.exportCsv(10000 * 100, 2000, (process) => {
          // 进度条更新
          this.csvProcess = process;
        });
        const endTime = performance.now();
        console.log(((endTime - startTime) / 1000).toFixed(2))
      } catch (error) {
        alert(error);
      } finally {
        this.pending = false;
      }
    },
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

时间为6.60s

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值