前端性能优化
性能分析
- 用谷歌浏览器打开检查界面,选择Performance(性能数据分析),点击左上角的record开始监控,操作一下界面,生成分析界面
- 时间轴,可以选择一小段的时间,分析这段时间的性能消耗
- network,查看后端接口调用的时间
- main,查看页面消耗的时间,包括js运行消耗的时间,DOM展示消耗的时间,
- summary,查看时间消耗占比
性能问题出现以下几种情况
- 方法本身耗时高
- 方法本身耗时虽然不高,但是调用了太多的子方法,导致总耗时高
性能优化记录
await setState导致render次数太多
const schema = await apiGetSchema()
await setState(this,{schema})
console.log(this.state.schema)
目前setState写法都是上面的形式,setState是异步方法,await等待setState异步方法结束,这样后面的this.state.schema才能获取到最新的数据,但是使用await setState会导致render方法呗多次调用,这是react框架的基本特性,所以尽量不用await setState
解决方法
//改为直接调用setState
this.setState({schema})
//直接调用setState会有一个问题:this.state无法获取发哦刚刚保存到state中的最新变量schema
console.log(this.state.schema)
//给setState传第二个参数,从this.state中获取到最新的变量schema
this.setState({schema},()=>{
console.log(this.state.schema)//能获取到最新的变量
})
增加shouldComponentUpdate减少render调用次数
当props或state发生变化时,render方法就会执行来更新内容
有些情况,props或state数据发生变化时,不影响页面展示内容,不需要执行render方法,此时就可以使用shouldComponentUpdate方法
shouldComponentUpdate(nextProps,nextState){
const comparator = (1,r)=>{
if(typeof 1 == 'function'){
return true
}
}
return !(_.isEqualwith(nextProps,this.props,comparator)&&(_.isEqualwith(nextState,this.state,comparator))
}
参数nextProps,nextState分别表示变化之后的props和state
this.props,this.state分别表示变化之前的props和state
方法返回true,则需要执行render,返回false,则不需要执行render
对函数式react使用react.memo
//stringField是一个函数式的react组件
function stringField(props){
//...
}
export default stringField;//改之前
export default React.memo(stringField);//改之后
函数式react组件,没有地方写shouldComponentUpdate方法,子类可以继承父类的shouldComponentUpdate方法,也起到作用.
对class类型的组件使用extends React.PureComponent
//改之前
class QueryList extends React.Component{}
//改之后
class QueryList extends React.PureComponent{}
React.PureComponent实现了shouldComponentUpdate方法,子类可以继承父类的shouldComponentUpdate方法,无需再写代码实现shouldComponentUpdate方法
但是PureComponent中的shouldComponentUpdate方法,只对props和state做了浅比较,会出现以下问题
- 问题1
state变化前
state = {
data:{
custName:'a'
}
}
state变化后
state = {
data:{
custName:'b' //需要更新时,页面不刷新
}
}
- 问题2
const list = [1,2,3,]
state变化前
state={
dataSource:[...list]
}
state变化后
state={
dataSource:[...list]//不需要更新render时,页面刷新了
}
dataSource从list中拷贝了一份数据,导致dataSource变化了,PureComponent.shouldComponentUpdate返回true,导致页面刷新.
结论:如果要展示的数据不再state浅层,而在state深层,或者数组或对象被拷贝后重新放到state上,PureComponent.shouldComponentUpdate都不可用,需要单独实现shouldComponentUpdate方法.