从合并请求角度谈性能优化

  性能优化是前端非常重要的一块,可下手的地方有很多,比如图片层次、JS层次、webpack工程层次、CSS层次、CDN层次等等,其中关于请求的优化是整个项目运行中非常重要的一块,所以这次我们来讲一下请求优化的一个小方法。

来看需求

  最近在一个React项目中有看见一个类似结构的代码,其中reqData、reqListData、reqProData是三个函数,内部分别有三个不同的Promise请求,请求获得数据后,将数据保存至this.state中。

componentDidMount() {
    this.reqData();
    this.reqListData();
    this.reqProData();
}

/**
 * 第一个请求
 **/
reqData() {
    ajax.getData().then(res => {
        // do something with this.setState({})
    })
}

/**
 * 第二个请求
 **/
reqListData() {
    ajax.getListData().then(res => {
        // do something with this.setState({})
    })
}

/**
 * 第三个请求
 **/
reqProData() {
    ajax.getProData().then(res => {
        // do something with this.setState({})
    })
}

  事实上,这段代码是没有问题的,毕竟在这个需求中,这三个返回的数据都是互不干扰互不联系的,但是在我们开发的过程中,我们需要有想到可能日后在每个地方都会有变动的地方,假如在后续开发中,我们在第二个请求的时候,需要根据第一个请求返回的数据进行判断再插入this.state中呢?这是一个非常有可能性的需求。

  而且值得注意的是,这是一个React项目,使用this.setState的时候,会触发render方法重新渲染你的界面(这里不考虑其他的,如shouldComponentUpdate等情况),那么这样来构建代码,会产生非常多次的无必要的render,严重影响性能。

  那么我们的需求就很清晰了,我们需要将多次的render缩减为一次,并使得请求返回的数据能够互相有业务逻辑来往,所以在这里,我们选择使用Promise.all

Promise.all

  Promise.all大家应该不陌生,作为ES6中作为Promise的伴生静态方法,他有一个显著功效:将多个Promise对象实例包装,生成并返回一个新的Promise实例。

  使用这个方法,你可以将多个的Promise以数组参数的形式传入,当所有Promise实例全部(注意是全部)变为resolve后,该方法才会返回,并可在then方法中获得一个数组形式的结果,你可以使用数组解构的方法轻松获取这些参数

// 使用方法
Promise.all([p1, p2, p3]).then(function (results) {
    let [res1, res2, res3] = results;
});

  下面的是博主给大家写的示例,让大家简单的了解一下这个Promise.all的使用方法。

// 示例
let promise1 = new Promise(function (resolve, reject) {
    if (true) {
        resolve(1);
    } else {
        reject(false);
    }
});
let promise2 = new Promise(function (resolve, reject) {
    if (true) {
        resolve(2);
    } else {
        reject(false);
    }
});
let promise3 = new Promise(function (resolve, reject) {
    if (true) {
        resolve(3);
    } else {
        reject(false);
    }
});

Promise.all([promise1, promise2, promise3]).then(function (results) {
    let [res1, res2, res3] = results;
    console.log(res1);
    console.log(res2);
    console.log(res3);
    if (res2 === 2) {
        console.log(res3 * 3);
    }
    // do something with this.setState({})
});
解决

  OK那么接下来方向就很明确了,于是我将componentDidMount中的代码修改成了以下的结构。


componentDidMount() {
    // ajax此处的ajax只是自己的封装,实际上ajax.reqData()等参数还是 Promise 格式
    Promise.all([ajax.getData(), ajax.getListData(), ajax.getProData()]).then((results) => {
        const [res1, res2, res3] = results;
        // 将结果作为参数传入,根据内部逻辑返回需要setState的数据
        const { data } = this.reqDataFormat(res1);
        const { list } = this.reqListDataFormat(res2);
        const { pro } = this.reqProDataFormat(res3);
        if (list) {
            // pro = list.res;
            // Do something with side effects
        }
        this.setState({ data, list, pro })
    });
}

  合并请求后根据测试,耗时不增反而略有下降,可读性上升,减少三次rander,性能提高。

版权声明:本文为JobsOfferings原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/JobsOfferings/p/React_Promise_all.html