1.需求背景

前端页面实现大文件(G级别以上)下载,压缩文件格式(tar包), 显示下载进度

2.需求分析:

如果页面上实现一个点击下载的功能,传统做法:
1.是使用一个 a 标签,然后将该标签的 href 属性地址指向下载文件在服务端的地址,增加download属性(同域);
2. location.href直接赋值(如果该文件能在浏览器上打开,那么就直接打开)
以上两种方法不做过多介绍,本文章主要是通过对文件进行切片传输,以流的形式返回给前端,前端进行整合实现下载
在这里插入图片描述

3.实现方式

import {saveAs} from ‘file-saver’;

 点击下载的函数(递归实现)
 async downloadLog(val: Row) {
        const requestHandle = async () => {
            const params = {
                date,
                number: val.packageNum  // 当前的切片索引
            };
            let {context, flag, total} = await this.fetchLogDownloadAction(params);
            val.dataStream.push(`${context}`); // 文件内容(base64)
            val.progress = ((++val.packageNum / total) * 100).toFixed(0); // 进度的百分比展示
            if (flag === 1) {
                // 最后一包
                val.packageNum = 0;
                this.saveFileDownload(val);
            } else if (flag === 0) {
                this.$nextTick(() => {
                    requestHandle();
                });
            }
        };
        requestHandle();
    }
 流文件保存本地并下载
 async saveFileDownload(val: Row) {
        let arrBlob: any[] = [];
        val.dataStream.forEach((ele: string) => {
            var bstr = atob(ele),
                n = bstr.length,
                u8arr = new Uint8Array(n);
            while (n--) {
                u8arr[n] = bstr.charCodeAt(n);
            }
            arrBlob.push(u8arr);
        });
        let saveFile = new Blob(arrBlob, {type: 'application/x-tar'});
        saveAs(saveFile, val.date);
        val.dataStream = [];
    }

4.实现方式解析

1.递归调用接口获取数据流(base64/blob),我这里后端接口返回的是base64;

2.后端对文件进行切片处理,接口返回流数据和总切片数以及当前的切片索引,前端进行进度计算,和流数据整合;

3.注意,不能对接收的base64数据流直接字符串拼接,否则会报错(Invalid string length),字符串长度超过了 JS 引擎的限制,那么这个长度限制到底是多少呢?根据搜索到的结果,V8 引擎支持的字符串长度为 2 的 29 次方,换算成内存量约为 512 MB;

4.解决办法,以数组的方式,进行保存

5.循环数组,把每一个切片base64数据转成Blob格式

6.调用file-saver的saveAs的api实现下载

5.可优化点

增加暂停/继续、取消按钮对进度条进行控制,实现断点续传;

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐