前端仅靠一个分页查询接口做数据导出,且保证同一时间段只有一个请求,兼容谷歌49,涉及promise、async、await、file-saver、xlsx.full、Generator函数

最近遇到个需求,按照顺序发送请求获取所有请求返回的数据组装成一个数组,并且这些请求必须一个一个来,在上一个请求未获取到数据前不能发送下一次请求,然后用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;
		}

写的稍微繁琐了点,因为涉及到的东西不少,代码有兴趣的小伙伴可以自行优化,下次见

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值