本文涉及到的知识:
- Promise,all()的使用
- js处理机制
- reduce的用法
- map的用法
- 同步异步
需求:
一个页面中需要用到多个字典数据。用于下拉选项,同时,需要将其保存为json格式。以便于key,value的相互转换。
data(){
return{
codeList:[]
}
},
computed:{
confPropertyTypeOptions() {
return this.codeList.length ? this.codeList[0].options : [];
},
configurationTypeOptions() {
return this.codeList.length ? this.codeList[1].options : [];
},
},
created(){
let codeType = ['confPropertyType', 'configurationType'];
let arrTemp = [];
let promiseList = codeType.map(type => getCode(type));
Promise.all(promiseList)
.then(res => {
// arrTemp = res.map(v => {
// if (Array.isArray(v.data) && v.data.length > 0) {
// const arr = v.data;
// let json = {};
// for (let i in v.data) {
// let item = v.data[i];
// json[item.ctCode] = item.ctName;
// }
// return {
// options: arr,
// json: json,
// };
// }
// return { options: [], json: {} };
// });
arrTemp = res.reduce((prev, current) => {
if (
Array.isArray(current.data) &&
current.data.length > 0
) {
const arr = current.data;
let json = {};
for (let i in current.data) {
let item = current.data[i];
json[item.ctCode] = item.ctName;
}
prev.push({
options: arr,
json: json,
});
return prev;
}
}, []);
this.codeList = arrTemp;
})
.catch(() => {
this.$message.error('查询类型失败');
});
}
getCode(codetype)
是一个post请求。通过字典类型获取字典数据。
最开始是这么实现的:
created() {
let codeType = ['confPropertyType', 'configurationType'];
codeType.forEach(code => {
getCode(code).then(res => {
if (
Array.isArray(res.data) &&
res.data.length > 0
) {
const arr = res.data;
let json = {};
for (let i in res.data) {
let item = res.data[i];
json[item.ctCode] = item.ctName;
}
this.codeList.push({
options: arr,
json: json,
});
})
})
}
坑1:然而初始化页面的时候报错:compute里边的options值获取不到。为什么呢?
因为:compute属性里的this.codeList.length
在第一次push的时候就不为0了,所以会报错。this.codeList.length
此时的长度为1。
优化后:
用一个临时数组去保存一下请求拿到的值,等foreach完成后再去赋值给codeList变量。
created() {
let arrTemp = [];
let codeType = ['confPropertyType', 'configurationType'];
codeType.forEach((code,index) => {
getCode(code).then(res => {
if (
Array.isArray(res.data) &&
res.data.length > 0
) {
const arr = res.data;
let json = {};
for (let i in res.data) {
let item = res.data[i];
json[item.ctCode] = item.ctName;
}
arrTemp.push({
options: arr,
json: json,
});
})
if(index === codeType.length-1){
this.codeList = arrTemp
}
})
}
坑2:然后还是报错,但是我们的思路是正确的,就是等两次请求完成后,再去处理这个结果。
这里是因为getCode()是一个异步方法,这两次异步完成的时间是不确定的,有可能你的第一个getCode(异步)还没返回结果,forEach(同步)已经完事了。
需要了解一下js的异步处理机制。你的代码是一行行往下执行的,然后遇到一个异步方法(或者异步块),程序会把这个异步放到一个异步队列中,程序继续顺序执行,同时,异步队列中的块也在执行。不过它什么时候结束,你并不知道。
这是Promise方法就发挥作用了。如我们最开始的实现。
let promiseList = codeType.map(type => getCode(type));
这时的promiseList是一个拥有两个Promise对象元素的数组
promiseList = [new Promise(),new Promise()]
Promise.all(promiseList)
,这两个post请求完成后,在.then()中可以处理res数据。
然后就是res.map()与res.reduce()的用法与区别了。
reduce(handler,target)
1.handler是一个方法 (prevent,current) => {return prevent}
prevent是我们处理后的结果,用于返回,
current是当前累加器的元素
2.target是我们的目标结果,可以是array,string,obj等