需求:一个页面中需要用到多个字典数据。用于下拉选项,同时,需要将其保存为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等