闲来无事,想把以前一直想做的事验证一下,react的性能到底怎样?
和原生js相比呢?
下面老张从两个方面进行简单的测试
【数据渲染、数据更新】,
测试维度比较简单、结果仅供参考,欢迎交流拍砖!
测试环境
mac i5 8g 、chrome 68.0.3440、react 16.2
下面开始进行测试
测试1 数据渲染
渲染条数1w条,为什么是1w,数据量太小不容易看到差距,真实场景不会有这样的场景,都是通过分页展示很少的数据,所以得出的结果并不实际;
react 代码先行
import './performence.less';
import React,{Component} from 'react';
import TestItem from './components/TestItem';//子组件
export default class Performance extends Component{
constructor(props){
super(props);
this.state={
page:'性能测试',
itemArr:[],//要渲染的数据列表
}
}
init={
max:10000,//渲染的条数
initMountTime:0//初始时间毫秒
}
//填充数据 ,更改数据
componentDidMount=()=>{
this.init.initMountTime=+new Date();
let max=this.init.max;
let i=0;
let itemArr=this.state.itemArr;
for(;i<max;i++){
itemArr.push({
title:'我是第'+i+'项'
});
}
this.setState({
itemArr:itemArr
})
}
//每一条数据单机事件,改变当前的title
itemClick=(index)=>{
let oldArr=this.state.itemArr;
oldArr[index].title="我被选中了------"+index;
this.setState({
itemArr:oldArr
})
}
componentWillUpdate=()=>{
this.init.initMountTime=+new Date();
}
componentDidUpdate=()=>{
console.log(this.init.max,'条react渲染所需时间',(+new Date()) - this.init.initMountTime,'ms');
}
render(){
return <main className="common-con-top">
{this.state.itemArr.map((item, index) => <TestItem key={index} title={item.title} index={index} itemClick={this.itemClick}></TestItem>)}
</main>
}
}
//子组件
import React from 'react';
export default class TestItem extends React.Component{
constructor(props) {
super(props);
}
render(){
return <div onClick={this.props.itemClick.bind(this, this.props.index)} className="testItem"><span>{this.props.title}</span></div>
}
}
原生代码
//也是基于react 进行编写和初始化,只是数据项用原生渲染
import './performence1.less';
import React, { Component } from 'react';
export default class Performance1 extends Component {
constructor(props) {
super(props);
this.state = {
page: '性能测试',
itemArr: []
}
}
init = {
max: 10000,
initMountTime: 0
}
//原生js生成数据项
componentDidMount = () => {
this.init.initMountTime = +new Date();
let max = this.init.max;
let i = 0;
let html='';
for (; i < max; i++) {
html +='<div class="testItem"><span>我是第'+i+'项</span></div>'
}
document.getElementById('div_demo_id').innerHTML=html;
console.log(this.init.max, '条原生渲染所需时间', (+new Date()) - this.init.initMountTime,'ms');
}
componentWillUpdate = () => {
}
componentDidUpdate = () => {
}
render() {
return <div id="div_demo_id"></div>
}
}
请看测试结果
这个测试结果看似差距很大,但是实际情况不会有直接渲染1w条的情况,如果将数据量再缩小后,差距也存在,但是性能是可以接受的!
测试2 更新数据
点击其中一条数据后标题改变,咱们来看看执行需要多长时间,还是基于1w的数据
react 事件处理代码 以及 用时计算
itemClick=(index)=>{
let oldArr=this.state.itemArr;
oldArr[index].title="我被选中了------"+index;
//oldArr.splice(index,1);
this.setState({
itemArr:oldArr
})
}
componentWillUpdate=()=>{
this.init.initMountTime=+new Date();
}
componentDidUpdate=()=>{
console.log(this.init.max,'条react渲染所需时间',(+new Date()) - this.init.initMountTime,'ms');
}
原生事件处理
componentDidMount = () => {
this.init.initMountTime = +new Date();
let max = this.init.max;
let i = 0;
let html='';
for (; i < max; i++) {
html +='<div dataindex="'+i+'" class="testItem">我是第'+i+'项</div>'
}
document.getElementById('div_demo_id').innerHTML=html;
console.log(this.init.max, '条原生渲染所需时间', (+new Date()) - this.init.initMountTime,'ms');
document.getElementById('div_demo_id').addEventListener('click',(e)=>{
if (e.target.nodeName === 'DIV'){
e.target.innerHTML='我被选中了----'+e.target.getAttribute('dataindex')
}
});
}
react 执行结果
原生的处理时间我没贴,因为使用的是事件代理 直接修改的当前的节点,耗时可以忽略不计了;
react的这个耗时貌似有点高,那有没有可以优化的手段呢? react其实已经提供了,那就是shouldComponentUpdate
看代码
// 在子组件内部增加一个方法 刚才咱们修改的是标题,那就通过标题来进行处理
shouldComponentUpdate(nextProps,nextState){
if(nextProps.title!==this.props.title){
return true;
}
return false;
}
// 下面在看下测试结果
进行简单的优化后性能有所提升,提升了50-70ms ,这也是我什么要提取一个子组件出来;
个人结论 通过上面的两个简单的测试,发现react性能和原生性能存在一定的差距,同时react提供我们可以优化的空间,react给到的是相对差不多的性能,并不是说虚拟dom比原生的快,只是react的组件化思想是一种全新得突破,让我们尽可能的少的操作dom,不用过多的考虑性能问题也能开发出性能差不多,过的去的应用;
仅供参考,欢迎交流和指正。