最近遇到个需求,按照顺序发送请求获取所有请求返回的数据组装成一个数组,并且这些请求必须一个一个来,在上一个请求未获取到数据前不能发送下一次请求,然后用table把数据装起来在前端做execl文件导出(不出意外的话应该是循环+promise+async+await+file-saver+xlsx.full,emmm,百度、csdn、cv、修改、调试然后完工哈哈哈)
file-saver和xlsx.full是两个前端数据导出的工具,github上可以直接下载源码
file-saver:https://github.com/eligrey/FileSaver.js
xlsx.full:https://github.com/protobi/js-xlsx
首先是一定数量的相同接口调用按照同步顺序执行,就是上一个接口没有返回结果之前不会执行下一个接口调用,这个js同步异步感觉从字面上来理解容易误解,同步是指js代码按编写的顺序执行,(个人理解,这样说感觉还是有点欠妥,因为js是解释型语言,在用户执行时才进行编译然后执行)
console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);
console.log(6);
这是一段同步代码
依次按顺序打印123456
console.log(1);
console.log(2);
console.log(3);
setTimeout(function () {
console.log(4)
},1000)
console.log(5);
console.log(6);
打印123564
现在就相当于要将所有请求及请求的结果按照同步代码来执行,最后组合成最终的数据,然而请求结果的获取都是异步的,所以每一个请求结果的获取用await修饰这里因为兼容就改成了yield,而函数则用*创建Generator函数
参考了这篇文章https://blog.csdn.net/Scoful/article/details/103701308
testApi(){
let _this = this;
let arr = [];
async function orderApi(){
for(let i = 0; i < 9; i++){
let data = await _this.getOne(i);
arr.push(data);
console.log(i);
}
console.log(arr);
};
orderApi();
},
getOne(i){
let data = new Promise((resolve,reject)=>{
this.axios.get("/",{params:{order:i}})
.then(res=>{
resolve(res.data);
})
.catch(err=>{
reject(err);
})
});
return data;
}
然而,,,谷歌浏览器49不支持async(這裡省略吐槽一篇文章,没办法工作环境不得不做兼容),不做兼容的同学再见吧,我继续,,,
这里推荐一个看兼容的网站 can i use https://caniuse.com/,在里面发现49版本谷歌支持Generator函数,async和await其实就可以用Generator来实现。然后参考了这篇文章https://blog.csdn.net/dream2222222222/article/details/107185446,然后自己再改造一下,因为es6的let cosnt 箭头函数 结构复制等等这么老的浏览器肯定也不支持啦,搜了一下let,谷歌49竟然支持
// 數據導出
exportToExcel(id){
var _this = this;
var fixed_table,data,table_write,total_page,now_data,size;
var api_arr = [];
var data_list = [];
if(_this.total_num === 0){
tipsCon("當前查詢項目0條!","center");
return
};
size = 100; //數據分塊大小
total_page = Math.ceil(_this.total_num/size);
for(var i=1;i<=total_page;i++){
api_arr.push({
now_page: i
});
}
function* loopApi(){
for(var i = 0; i <api_arr.length; i++){
now_data = yield _this.getOneSliceData(size,api_arr[i].now_page);
data_list = data_list.concat(now_data);
// console.log(api_arr[i].now_page);
}
// console.log(data_list);
vm.exportList = data_list;
};
function asyncToGenerator(generatorFunc) {
return function() {
var gen = generatorFunc.apply(this, arguments)
return new Promise((resolve, reject) => {
function step(key, arg) {
var generatorResult
try {
generatorResult = gen[key](arg)
} catch (error) {
return reject(error)
}
// const { value, done } = generatorResult;
var value = generatorResult.value;
var done = generatorResult.done;
if (done) {
return resolve(value)
} else {
return Promise.resolve(value)
.then(function (val) {
step("next", val)
})
}
}
step("next")
})
}
}
var yel = asyncToGenerator(loopApi);
loadPreview("show");//这个是加载动画,自己封装的函数
_this.un_export = false;
yel()
.then(function () {
tipsCon("數據準備完成,開始導出!","center");
_this.$nextTick(function () {
fixed_table = document.querySelector(`#${id}>.el-table__fixed`);
if(fixed_table){ //判断要导出的节点中是否有fixed的表格,如果有,转换excel时先将该dom移除,然后append回去
data = XLSX.utils.table_to_book(document.querySelector(`#${id}`).removeChild(fixed_table));
document.querySelector(`#${id}`).appendChild(fixed_table);
}else{
data = XLSX.utils.table_to_book(document.querySelector(`#${id}`));
}
table_write = XLSX.write(data, {
bookType: "xlsx",
bookSST: true,
type: "array"
});
try {
saveAs(
new Blob([table_write], { type: "application/octet-stream" }),
"機台設置數據.xlsx"
);
} catch (e) {
if (typeof console !== "undefined") console.log(e, table_write);
}
return table_write;
})
})
.then(function () {
loadPreview("hide");
tipsCon("數據導出完畢!","center");
vm.exportList = [];
_this.un_export = true;
})
.catch(function (err) {
loadPreview("hide");
tipsCon("數據填充出錯!","center");
_this.un_export = true;
console.log(err);
})
},
getOneSliceData(size,now_page){
var data,new_pro;
data = {
"search": "查詢條件",
"pageNum": now_page,
"pageSize": size,
};
new_pro = new Promise(function (resolve, reject) {
doQuery(data)//这个是一个返回promise对象的接口封装函数,根据查询条件和页码和每页展示数据量获取数据
.then(function (res) {
resolve(res.resultMap.resultList);
})
.catch(function (err) {
reject(err);
})
})
return new_pro;
}
写的稍微繁琐了点,因为涉及到的东西不少,代码有兴趣的小伙伴可以自行优化,下次见