Skip to content

ReactNative Macos首屏时间开销测量 #138

@smallnewer

Description

@smallnewer

RCTRootView init时会发生一系列开销,这些开销导致即使是空的RN页面,也会有200ms左右的白屏时间,测量这些目的是为了消灭闪屏感和等待感,尽量达到和native类似的一帧内渲染结束的极速反馈。

2019-01-02 4 03 23

在init时,主线程会初始化所有的native模块,然后创建JS线程和Bridge线程,紧跟着开始加载JS代码。当这些都完成后,Bridge线程会收到notify然后开始告诉JS线程执行加载好的代码。在JS代码执行期间,会产生一系列的native call,这些call会在整个JS代码执行完毕后才会flush出去,此时主线程才会执行指定的组件,结束整个调用过程。

这里面耗时主要占用者是线程间的notify(100ms)和JS代码执行(200ms),整个过程耗时也才300ms。这两个都不太好解决,目前在业务方的方案只能想到预创建。

预创建需要考虑两个问题,一个是组件的开销占用多少(上面测量未包含);一个是闪屏问题。

先说第一个,经过测量,100图文量级大约在1~6ms能完成,基本没太大问题,配合上异步渲染会更好。

第二个的问题是比较难搞,当一个RCTRootView(包括webview)第一次插入到渲染队列时会间隔一两帧(目测)才会真正渲染出来(即使它是预创建好的),在删除节点到几十ms后出来的画面就会造成闪烁感,至于具体的导致的机制和原因不太清楚。解决办法的话倒是有两个思路:1. 预创建完时,也插入到渲染树里,但设置为透明,这样可以消除这一两帧的空白。2. 在插入到渲染树时,延迟一会删除旧的节点,但具体的时间并不好把握。

预创建的缺点有二:

  1. 多个RN页面依赖同一套JS,才能提前消耗JS执行的200ms,如果每个页面的业务JS都不一样(比如页面来自不同的团队,但都嵌套在同一个APP内),效果会打折扣,虽然我们可以把lib部分抽出,但业务代码也会消耗很多时间;
  2. 首次打开的时间依旧是慢的。

至于缺点,只能针对具体业务场景针对性优化了。相信上面的方案也能应付不少场景了。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions