需求:一個頁面中需要用到多個字典數據。用於下拉選項,同時,需要將其保存為json格式。以便於key,value的相互轉換。記錄在實現過程中踩的坑

本文涉及到的知識:

  1. Promise,all()的使用
  2. js處理機制
  3. reduce的用法
  4. map的用法
  5. 同步非同步

需求:

一個頁面中需要用到多個字典數據。用於下拉選項,同時,需要將其保存為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等

Tags: