从合并请求角度谈性能优化
从合并请求角度谈性能优化
性能优化是前端非常重要的一块,可下手的地方有很多,比如图片层次、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,性能提高。