这条路走不通了,我们完全可以换一个思路,背景7000个格子,再加上1400个事件,用户屏幕有那么大吗,看得完吗?肯定是看不完的,既然看不完,那我们只渲染他能看到部分不就可以了!按照这个思路,我们找到了一个库:react-visibility-sensor。这个库使用方法也很简单:
function MyComponent (props) { return ( <VisibilitySensor> {({isVisible}) => <div>I am {isVisible ? 'visible' : 'invisible'}</div> } </VisibilitySensor> ); }结合我们前面说的,我们可以将VisibilitySensor套在Background上面:
class Background extends PureComponent { render() { return ( <VisibilitySensor> {({isVisible}) => <Event isVisible={isVisible}/> } </VisibilitySensor> ) } }然后Event组件如果发现自己处于不可见状态,就不用渲染了,只有当自己可见时才渲染:
class Event extends Component { render() { const { selected } = this.context; const { isVisible, event } = this.props; return ( { isVisible ? ( <div className={ selected === event ? 'class1' : 'class2'}> 复杂内容 </div> ) : null} ) } } Event.contextType = SelectContext;按照这个思路我们又改了一下,发现性能又提升了,整体时间下降到了大概4.1秒:
仔细看上图,我们发现渲染事件Rendering时间从1秒左右下降到了43毫秒,快了二十几倍,这得益于渲染内容的减少,但是Scripting时间,也就是脚本执行时间仍然高达4.1秒,还需要进一步优化。
砍掉mousedown事件渲染这块已经没有太多办法可以用了,只能看看Scripting了,我们发现性能图上鼠标事件有点刺眼:
一次点击同时触发了三个点击事件:mousedown,mouseup,click。如果我们能干掉mousedown,mouseup是不是时间又可以省一半,先去看看他注册这两个事件时干什么的吧。可以直接在代码里面全局搜mousedown,最终发现都是在Selection.js,通过对这个类代码的阅读,发现他是个典型的观察者模式,然后再搜new Selection找到使用的地方,发现mousedown,mouseup主要是用来实现事件的拖拽功能的,mousedown标记拖拽开始,mouseup标记拖拽结束。如果我把它去掉,拖拽功能就没有了。经过跟产品经理沟通,我们后面是需要拖拽的,所以这个不能删。
事情进行到这里,我也没有更多办法了,但是响应时间还是有4秒,真是让人头大
反正没啥好办法了,我就随便点着玩,突然,我发现mousedown的调用栈好像有点问题:
这个调用栈我用数字分成了三块:
这里面有很多熟悉的函数名啊,像啥performUnitOfWork,beginWork,这不都是我在React Fiber这篇文章中提过的吗?所以这些是React自己内部的函数调用
render函数,这是某个组件的渲染函数
这个render里面又调用了renderEvents函数,看起来是用来渲染事件列表的,主要的时间都耗在这里了
mousedown监听本身我是干不掉了,但是里面的执行是不是可以优化呢?renderEvents已经是库自己写的代码了,所以可以直接全局搜,看看在哪里执行的。最终发现是在TimeGrid.js的render函数被执行了,其实这个是不需要执行的,我们直接把前面歪门邪道的shouldComponentUpdate复制过来就可以阻止他的执行。然后再看下性能数据呢: