【译】React Native - 同步和异步渲染性能

4,618 阅读5分钟

原文地址:React Native – Sync & Async Rendering Performance

原文作者:Parashuram

React Native是一个使用JavaScript和React构建本机移动应用程序的框架。使用React Native编写的Android和iOS应用程序利用平台的用户界面元素来确保它们看起来和感觉像本机应用程序。

在这篇文章中,我们将看看React和React Native之间的相似点和不同点,两个系统如何在架构上融合,以及从性能角度来看的含义。

React Native就像React

这些应用程序的业务逻辑是用JavaScript和React编写的,并在一个运行在单独线程上的JavaScript虚拟机上执行。与React Web应用程序一样,用户界面使用React组件树进行声明性构造。React Native组件树中的叶节点使用“View”和“Text”,而不是像“div”或“span”那样使用DOM原语。因此,当React 协调程序运行时,创建节点或集合属性的命令将指向UIView或android.View代替标准DOM元素。

.....但是在一个单独的线程上(今天)

但是,与Web不同,JavaScript代码不是在UI线程上执行,而是在运行JavaScript VM的后台线程上执行。这种线程分离会产生有趣的结果,其中之一是确保UI线程平滑,并且不会因JS代码中发生的任何昂贵计算而减慢。例如,即使应用程序的不相关部分呈现非常复杂的用户界面,视图也将继续平滑滚动。两个线程之间的通信是非阻塞和异步的。今天,React Native使用“桥”将排队的UI操作发送到UI线程。

React Native的这种异步特性也有利于其布局系统,并且非常适合性能。React Native中的样式与Web类似,并使用Flexbox指定。由于Android和iOS本身并不了解Flexbox,因此React Native捆绑了Yoga,这是一个布局系统,在给定flexbox输入样式的情况下输出组件的相对坐标。就像JS代码一样,这种布局计算也可以在一个单独的非阻塞线程中执行。

下面是一个说明三个线程的图表,以及React Native今天的工作原理。 React Native的多线程架构

React Native的多线程架构
网上这样一个系统的最佳类比可能是一个实验(github.com/web-perf/re… Workers然后异步运行React和JS更新主线程。与React Native一样,Web Workers也会异步与主线程进行通信,并且是非阻塞的,这可能对性能有利。

多线程并不总是好的

在大多数情况下,在单独的线程上运行复杂的计算可以帮助保持主UI线程的自由和响应。但是,有些情况下,这种多线程可能会妨碍顺畅的用户体验。这里有几个例子。

  1. 就像渲染命令被发送到UI线程一样,来自用户交互的所有事件都将在UI线程上接收,并且需要被发送回JS VM进行处理。通信是异步的,因此处理JS代码中的事件也是如此。因此,我们无法同步取消事件或阻止默认操作。
  2. RecyclerViewUICollectionView这样的UI控件虚拟化长列表以提高性能。当需要基于滚动位置呈现“第n个元素”时,API需要同步返回值来呈现特定元素。在更抽象的术语中,将React Native与期望同步呈现的UI布局系统集成在一起现在更加困难。虽然React Native可能无法阻止滚动长列表,但如果这些列表非常长,它仍然会显示没有内容,并且滚动速度非常快。

以上也是为什么在Web Worker中运行React可能不值得复杂的原因。

同步和异步

虽然React Native今天只支持异步通信,但显然有一种情况可以支持两种类型的性能渲染。React Native的新架构旨在实现同步通信的情况。新的通信API更靠近Web,而不是使用桥接器并通过队列管道所有命令。

一个是Web,大多数DOM操作都是使用同步API进行的,例如:

var el = document.createElement('div'); 
el.setAttribute('style', '');
root.appendChild(el);

在上面的示例中,调用createElement返回本机特定于平台的对象。JavaScript可以继续使用该“不透明”对象,并将其添加到DOM树中。新的React Native API使用类似的JavaScript接口(也称为JSI)将C ++对象公开给JavaScript世界。因此,所有阵营的的命令createNode,或者mountNode可以是直接的,高性能的电话,像在浏览器中。根据事件,这也将允许在响应滚动等事件时在主线程上运行JavaScript代码,或者在渲染从网络返回的页面时在后台线程上运行JavaScript代码。

这种新架构还将能够利用React Fiber,从而可以灵活地安排UI更新。有关此新架构及其基本原理的更多信息,请参阅ReactConf 2018会话。这种融合类似于Web开始接受Worklets概念的方式。

结论

虽然React和React Native当前呈现给两种不同类型的表面,但它们共享许多常见的UI模式。React Native的新架构使移动设备的渲染更接近于在网络上的完成,为未来铺平了道路,我们可以在网络和移动平台之间共享更多代码。虽然每个系统都有一组API和限制,但我们可以从一个系统的性能模式中学习并将其应用到另一个系统。