需求:一個頁面中需要用到多個字典數據。用於下拉選項,同時,需要將其保存為json格式。以便於key,value的相互轉換。記錄在實現過程中踩的坑
本文涉及到的知識:
- 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等