很多人都知道react很快,甚至觉得用react完全不用考虑性能问题。为什么这么人为呢?因为他有visual dom 啊,是不是吧。那visual dom是什么来着?当然咱们这里不说他是个什么玩意儿,咱们就来测下react到底快不快!
总不能上来就上代码吧。那多low。我怎么也得铺垫一下,给大家缓冲一下哈。
看我临时编个故事来,如果表达的有些尴尬请大家尽量挺住。实在挺不住,那就使劲鼓掌。很久很久以前,小黑和老白聊天,小黑说你这react东西就是好用啊,直接可以再js里写html,而且没有dom操作,总算是抛弃当前年的jq了,而且我随便怎么写都是渲染的那么快,这性能果然是快啊。老白深深叹了一口气,感觉这孩子没救了。react性能真的那么高吗?他比jq速度快?你这只是开发感受而已,况且你做的那个东西以为我不知道吗,一个页面上没几个东西,你就自己骗自己吧。老白是小黑的领导,当然是不敢直言反驳了,弱弱的回答一句这react的特点不就是挺快的吗。。。不过小黑没在说,他是挺聪明的自己赶紧去做个测试去了,到底是原生快还是react快。
小黑给自己定了两个测试维度【初次渲染、更新渲染】。
测试环境如下:
mac i5 8g 、chrome 68.0.3440、react 16.2
小黑的机器还可以啊。小土豪啊。
下面开始进行测试
首次数据渲染
渲染条数1w条,为什么是1w,数据量太小不容易看到差距,真实场景不会有这样的场景,都是通过分页展示很少的数据,所以得出的结果并不实际;
react 代码先行 渲染1w
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> } }
原生代码 渲染1w
//也是基于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> } }
小黑鼓捣了半天,终于运行出结果来。【这家伙比较懒,得先弄react的环境】
看了结果之后,小黑有点呆了。竟然差距那么大。之前的主观判断还真是打脸啊,现在更疼了。
别急咱还没测完呢。
更新数据
点击其中一条数据后标题改变,咱们来看看执行需要多长时间,还是基于1w的数据,毕竟react的更新的思路和咱们以往的操作dom是不同的,所以有必要看下。
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
code哪里跑
// 在子组件内部增加一个方法 刚才咱们修改的是标题,那就通过标题来进行处理 shouldComponentUpdate(nextProps,nextState){ if(nextProps.title!==this.props.title){ return true; } return false; } // 下面在看下测试结果
结果发生了稍微的变化,但是小黑顿悟了。
进行简单的优化后性能有所提升,提升了50-70ms ,这也是我什么要提取一个子组件出来;
小黑最后得出一个结论 通过上面的两个简单的测试,发现react性能和原生性能存在一定的差距,同时react提供我们可以优化的空间,react给到的是相对差不多的性能,并不是说虚拟dom比原生的快,只是react的组件化思想是一种全新得突破,让我们尽可能的少的操作dom,不用过多的考虑性能问题也能开发出性能差不多,过的去的应用;
小黑长叹一口气,react还真是让人脑瓜疼啊。还得继续研究啊。不巧的是碰到了老白,微微一笑然后走开,不带走一丝尘埃。
故事到此结束!
总结
其实很多时候我们虽然接受了一个新事物,但是我们对他的了解只是表面的肤浅的。更深层次的东西需要我们花更多的精力去探索。代码写的一般般,不过瑕不掩瑜哈,能说明问题。代码不重要,重要的是对他的认知和理解。从这里开始,不要再觉得react有多快了,小项目没事,你试试搞个大的玩玩。真不需要优化的话那你就是最帅的地球人。