大批量数据导出/前端导出数据实践

场景

我们PHP程序员在整个工作流程中,难免要和CRM/ERP之类的系统打交道。数据表格导出是在常见不过的功能模块。在数据量比较小的时候,我们可以随便搞,直接设置header头,输出csv也是可以的。但是当数据量上来的时候,我们会面临但不局限于以下问题:

1.php脚本执行超时;

2.可用内存不足;

3.nginx超时。

解决方案

所以很自然的想到,那能不能把文件下载/导出/保存这个动作放到前端来执行呢,这样还可以节省服务器资源。我觉得这是个不错的主意。
先上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//依赖的JS工具库
//github https://github.com/sheetjs/sheetjs
<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
exportData() {
//dialog控制开关
this.dialogVisible = true;
/* original data */
let date = new Date();
let filename = date.getFullYear() + '' + (date.getMonth() + 1) + '' + date.getDate() + "列表.xlsx";
let insertData = [];
let header = [
'用户id',
'手机号',
'姓名'
];
insertData.push(header);
//在vue里为了不影响数据做一下深拷贝
let tmpData = JSON.stringify(this.$data);
let tmpParamObj = JSON.parse(tmpData);
let totalPage = this.total_page;
let totalCount = this.total_count;
const that = this;
for (let i = 1;i<=totalPage;i++) {
tmpParamObj.current_page = i;
//去掉没用的数据
tmpParamObj.list = [];
tmpParamObj.pagination = [];
$.ajax({
url: '/demo/demo/demo/getList',
method: 'POST',
data: {'_token': '{{csrf_token()}}', data: tmpParamObj},
success: function (data) {
console.log(data);
if (data.status == 'success') {

data.data.forEach((item, index) => {
let tmp = [];
tmp.push(item.PassportID);
tmp.push(item.MobileNumber);
tmp.push(item.RealName);
insertData.push(tmp);
});
//记录下载进度更新到dialog上的下载进度条
let percent = Number.parseInt((insertData.length - 1) / totalCount * 100);
console.log(percent);
that.download_percent = percent;
if (percent === 100) {
let ws_name = "SheetJS";
let wb = XLSX.utils.book_new();
let ws = XLSX.utils.aoa_to_sheet(insertData);
//
/* add worksheet to workbook */
XLSX.utils.book_append_sheet(wb, ws, ws_name);
console.log('【开始下载】' + new Date());
XLSX.writeFile(wb, filename);
console.log('【下载完成】' + new Date());
that.dialogVisible = false;
}
} else {
layer.msg('请求失败', {icon: 2});
}
},
dataType: 'json',
error: function () {
layer.msg('网络异常', {icon: 2}, function () {
layer.closeAll();
});
}
});
}
}

循环的按照页码去请求数据,直到拿到所有的数据。然后一并保存。理论上可以不担心数据的体量。新技能Get。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×