前人种树后人乘凉
原文地址
你需要了解什么是帧
在你的祖父辈,它们一般把视频称为”移动的图片”的一个原因是:视频中逼真的动作是以固定的速度,快速改变静态的图片创造出来一个错觉。这里的每一个图片就一个是帧。每一秒中图片的数量(帧),它直接影响了视频的真时性(或者app中的用户界面). iOS的设备是每秒60帧。它也就给了你以及UI系统大约16.67毫秒的时间,来完成生成一张静态图片(帧)的所有工作。如果你不能在16.67ms内完成,则你将会丢失一个帧,UI会出现无响应状态。
在你的应用程序中,打开Deveroper菜单,并切换到fps监视器,你会发现有两种不同的帧速率。
Javascript 帧速率
许多的React Native应用,你的业务逻辑都是运行在JavaScript线程上的。比如React 应用的生命周期(mount, update), API调用,触摸事件的处理等。并且在每一帧失效前, 更新原生支持的视图(Views)是被成批处理的,并且在每一次事件循环遍历结束后,发送给本地端。如果Javascript线程对于一个帧没有响应,则被认为删除这个帧。举例来说,在一个复杂的应用的root 组件中,你调用了this.setState. 它会导致重新宣染子组件,这个过程很消耗资源。可以假设为它将花费200ms, 那么导致12帧丢弃(200ms / 16.67ms)。通过Javascript控制的作何动画,在这个过程会被冻结。如果作何计算超过100ms, 用户就可以感受到。
当你添加一个新的路由,Javascript线程需要读取这个场景所需要的所有组件,然后通过适当的命令发送给本地端,创建视图。这个过程会花费多个帧,引起卡顿,这是因为transition是由Javascript控制的。有此组件会在componentDidMount中做额外的计算,这可能会导航在transition卡顿的第二个原因.
另一个例子是响应触摸:如果你要做的任务在Javascript线程上跨越多个帧,你可能会注意到TouchableOpacity的延迟。这就是在Javascript 线程在忙的时候,不能处理从主线程发送过来的触摸事件的原因,所以会出现,native view调整了透明度,而又不对触摸事件做出响应。
InteractionManager.runAfterInteractions(() => {
do something...
});
一、Console.log 语句
当运行一个打包好的app, Console.log语句会引起很大的瓶颈。它会包含调试库redux-logger, 所以在打包前,确保删除了Console.log语句.
二、ListView初始化时或者读取一个大的列表时很慢
我们可以通过以下的几个方面,改善部分性能
�initialListSize
这个属性用来指定我们第一次渲染时,要读取的行数。如果我们想尽可能的快,我们可以设置它为1, 然后可以在后续的帧中,填弃其它的行。每一次读取的行数,由pageSize决定.pageSize**pageSize
在使用了initialListSize之后,ListView根据pageSize来决定每一帧读取的行数,默认值为1, 但如果你的的views 非常的小,并且读取时占的资源很少, 你可以调整这个值,在找到适合你的值。scrollRenderAheadDistance
“以像素为单位,如何预读取要加载的行?”
如果我们的列表有2000个项,而让它一次性读取,它会导致内存和计算资源的耗尽。所以scrollRenderAhead distance可以指定,超出当前视口多省,继续宣染。removeClippedSubviews
“当它设置为true时,当本地端的superview为offscreen时 ,不在屏幕上显示的子视图offscreen(它的overflow的值为hidden) 会被删除。它可以改善长列表的滚动的性能,默认值为true.
这对于大的ListViews来说是一个非常重要。在Android, overflow的值通常为hidden. 所以我们并不需要担心它的设置,但是对于iOS来说,你需要设置row Container的样式为overflow: hidden