【译】React Native — 桥接Bridge 到 Fabric项目(RN新架构)

做者:Chen Feldmanhtml

发布日期:2019.07.30前端

原文连接:medium.com/swlh/react-…react

翻译中有部分是意译。ios

最近几年,React Native已经成为最流行的移动端App开发框架之一。解决了不少开发者常常思考的问题:应该使用原生开发客户端app,仍是使用web开发Hybird app。git

使用RN开发须要web方面的知识和React经验,由于它基本是基于React框架的。须要比直接使用Cordova这样库更难一些,可是比写Swift和Kotlin 这两个原生客户端的代码要轻松不少。RN能够经过写纯js代码得到和原生相似的性能体验。github

第一部分:RN的Bridge(桥接)是什么黑魔法?

在开始以前,咱们先介绍一下,相比于其余方案,React Native的定位是什么。web

img
在上图中,选取了一些常见的App开发方式。

从左到右,能够分红3个阵营:objective-c

  1. 原生Native。这意味着你想去使用原生语言开发App,好比ios的Swift或Android的Kotlin。确定会得到最好的性能,而且能够充分利用设备硬件和原生API。可是,这须要学习两种不一样的编程语言,维护两套代码,而且可能有双倍的bug,甚至须要有两个不一样的开发团队。编程

  2. Hybrid。若是你是web开发者或者拥有一个已经熟悉JS、HTML、CSS和某些前端库的Web团队,你能够选择这种方案,并使用Cordova/Ionic 经过一些步骤使你的网页变成移动App。这样咱们只须要学习一个技术栈,可是,在性能,硬件和API的使用上会有限制。react-native

  3. 类原生(其实也算是一种Hybrid)。React Native就属于这类,理论上开发者只须要懂得Web开发知识就能够了。可是学习曲线会比Hybrid要高一些。开发者须要学习怎么使用React Native的库。在某些场景下,可能还须要使用XCode或Android Studio打开项目。可是写的代码能够适用于iOS和Android两个平台,开发上的限制也会比Hybrid要小一些。性能表现会更像原生开发,并且能够更容易地使用一些原生的API。

如今咱们理解了RN的定位,让咱们对比一下RN和Hybrid的渲染状况:

img

从上图能够看出,使用Cordova的App是放在webView里的。这更像是一个在App里的浏览器。用web的概念说,这更像一个web app里的iFrame。

左边展现了React Native是怎么组成的,在RN中的每一个组件,好比:Text、Button、Image等都有一个相对应的原生组件。因此和不少新接触RN开发者想的不同,RN并无编译成原生代码,它作了个JS组件和原生组件的映射。

当咱们这样在Render函数里写了个RN组件:

img

背后部分预先写好的原生组件会是这样的:

img

若是咱们用iOS来举例,这些是RN里面的原生组件代码:

img

总的来讲,RN团队已经为咱们建立和映射了全部的原生组件。咱们须要去作的只是去基于RN组件和库写JavaScript代码。其余的部分对通常开发者来讲都是不可见的,像黑魔法同样。

因此,看上去咱们只用写js代码就能够了。让咱们一步步来解释一下这个架构是怎样的。从Bridge开始是最合适的:

RN能够分红JS 和 Native两部分,这两部分都有本身的线程

线程通讯是经过Bridge通讯,传输的是JSON信息,其中包含了module id,method id和一些须要的数据。这两边并不能直接地相互感知,也不能共享相同的内存。

img

这有点像不一样服务器之间通讯,若是你有用不一样语言写的后台服务,你将怎么在他们之间通讯呢?

不少人认为队列是一个很好的解决方案。你发送JSON/XML队列消息,这个消息听从相应的协议,而且每一个服务都知道怎么去读取和解析成对应的数据和行为。这个队列就很像RN里面的Bridge。

img

这里有个例子展现通讯是怎样进行的,信息被发送到Bridge。从建立新的View和样式并在屏幕上显示,到在移动端设置子组件和进行一些操做:

img

若是想要在console里看到Bridge的消息,只须要把下面这个代码片断放到index. < platform > .js里就能够了

img

如今咱们知道了RN是怎么通讯的,而且开始揭晓其中的“黑魔法”。

  • js代码和objective-c之间的通讯。RN在ios上使用的是内置的JSCore,在Android须要格外编译一个Js引擎
  • JS引擎知道如何去更加高效地把JS转换成机器语言。

这也是为何Android App须要更多的时间去加载,由于须要加载JSCore到项目里。不过在0.60.2以后,RN可使用Hermes,这对于RN来讲是更理想的JS引擎。

第二部分:Bridge是怎么工做的?

在这部分,咱们将经过解析从点击App图标到App打开这个流程和其中的一些相关细节。

img

为了理解RN是怎么在背后建立View的,咱们先须要解释一些基础概念:

  1. UIManager:在Native侧,是在iOS/Android里主要运行的线程。只有它有权限能够修改客户端UI。
  2. JS Thread:运行打包好的main.bundle.js文件,这个文件包含了RN的全部业务逻辑、行为和组件。
  3. Shadow Node/Tree:在Native层的一个组件树,能够帮助监听App内的UI变化,有点像ReactJS里的虚拟Dom和Dom之间的关系。
  4. Yoga:用来计算layout。是Facebook写的一个C引擎,用来把基于Flexbox的布局转换到Native的布局系统。

理解了上面的一些基础概念,让咱们来看下打开App时,每一步发生了什么:

  1. 用户点击App的图标

  2. UIManager线程:加载全部的Native库和Native组件好比 Text、Button、Image等

  3. 告诉Js线程,Native部分准备好了,Js侧开始加载main.bundle.js,这里面包含了全部的js和react逻辑以及组件。

  4. Js侧经过Bridge发送一条JSON消息到Native侧,告诉Native怎么建立UI。值得一提的是:全部通过Bridge的通讯都是异步的,而且是打包发送的。这是为了不阻塞UI,举个栗子:

img

  1. Shadow线程最早拿到消息,而后建立UI树

  2. 而后,它使用Yoga布局引擎去获取全部基于flex样式的布局,而且转化成Native的布局,宽、高、间距等。。

  3. 以后UIManager执行一些操做而且像这样在屏幕上展现UI:

    img

这些就是启动App是的主要步骤。

RN基于这个架构有如下优势:

  • UI不会被阻塞:用户感受到更加流畅
  • 不须要写Native侧的代码:使用RN库的话,不少代码能够只写JavaScript的
  • 性能更加接近Native
  • 整个流程是完整的。开发者不用去控制而且彻底了解它

可是,有优势确定也会有缺点。下面咱们介绍一下可以解决现有缺点的新架构:Fabric。

第三部分:Bridge的优缺点和Fabric架构

咱们已经讨论了RN的当前架构,是时候说一下其中的缺陷。能够看一下Facebook的React团队负责人在她博客里提到的。

当前架构的缺点是:

  • 有两个不一样的领域:JS和Native,他们彼此之间并不能真正互相感知,而且也不能共享相同的内存。
  • 它们之间的通讯是基于Bridge的异步通讯。可是这也意味着,并不能保证数据100%并及时地到达另外一侧。
  • 传输大数据很是慢,由于内存不能共享,全部在js和native之间传输的数据都是一次新的复制。
  • 没法同步更新UI。比方说有个FlatList,当我滑动的时候会加载大量的数据。在某些边界场景,当有用户界面交互,但数据尚未返回,屏幕可能会发生闪烁。
  • RN代码仓库太大了。致使库更重,开源社区贡献代码或发布修复也更慢。

不过不要误会,Facebook本身也正在使用React Native开发各类app,服务百万级的日活用户。同时也有其余有名的公司在生产环境中使用基于当前架构的RN,好比Wix、Bloomberg、Tesla、Zynga等等。

RN开发团队正着手去解决上面提到的缺点。

这是以前的RN架构:

当前结构的主要部分

这是新的架构图:

img

让咱们来解释一下这些新的概念:JSI,Fabric,Turbo Modules,和 CodeGen。

  1. JSI(将会替换Bridge) -- 为了让JS和Native可以互相感知。将再也不须要经过Bridge传输序列化JSON。将容许Native对象被导出成Js对象,反过来也能够。两侧也会导出能够被同步调用的API。实际上,架构的其余部分都是基于这个之上的(Fabric,Turbo Modules等,这些下面会解释)

  2. Fabric -- UIManager的新名称,将负责Native端渲染。和当前的Bridge不一样的是,它能够经过JSI导出本身的Native函数,在JS层能够直接使用这些函数引用,反过来,Native层也能够直接调用JS层。这带来更好更高效的性能和数据传输。

  3. Turbo Modules。记得上面的Native组件吗?Text、Image、View,他们的新名字叫Turbo Modules。组件的做用是相同的,可是实现和行为会不一样。第一,他们是懒加载的(只有当App须要的时候加载),而如今是在启动时所有加载。另外,他们也是经过JSI导出的,因此JS能够拿到这些组件的引用,而且在React Natvie JS里使用他们。尤为会在启动的时候带来更好的性能表现。

  4. CodeGen -- 为了让JS侧成为两端通讯时的惟一可信来源。它可让开发者建立JS的静态类,以便Native端(Fabric和Turbo Modules)能够识别它们,而且避免每次都校验数据 => 将会带来更好的性能,而且减小传输数据出错的可能性。

  5. Lean Core -- 是对React Native库架构的变化。目的是减轻lib的负担,并帮助社区更快地解决更多pull request。Facebook正在把库的某些部分拆分出来,经过关注Github就能够看出他们在这方面的行动了。好比这个:

    img

顺便一提,这里有个例子,你能够在Chrome里尝试一下,这也是JSI如何工做和导出对象的灵感来源:

在Chrome里打开开发者界面,而后输入console.log,回车。你将看到native code。这说明console.log实际上是一个Native的函数。

在Chrome里打开开发者界面,而后输入console.log,回车。你将看到native code

接下来咱们再对比一下使用新架构,App启动的流程是怎么样的。

  1. 用户点击App的图标

  2. Fabric加载Native侧(没有Native组件)

  3. 而后通知JS线程Native侧准备好了,JS侧会加载全部的main.bundle.js,里面包含了全部的js和react逻辑+组件

  4. JS经过一个Native函数的引用(JSI API导出的)调用到Fabric,同时Shadow Node建立一个和之前同样的UI树。

  5. Yogo执行布局计算,把基于Flexbox的布局转化成终端的布局。

  6. Fabric执行操做而且显示UI==>

    img

为了完成整个流程,咱们几乎作了一样的事情,可是没有了Bridge,如今咱们能够有更好的性能,咱们能够用同步的方式进行操做,甚至能够对UI上的同步操做进行优先级排序。启动时间也将更快,App也将更小。

因此,咱们何时能够上手使用这些东西?

能够在Github上关注它们各自的更新状况:

  1. JSI
  2. Fabric
  3. Turbo Modules
  4. Lean Core
  5. CodeGen

按理说,大多数的更改将逐步完成,并有但愿在2019第四季度或2020第一季度发布。

部分参考文档,便于更深入地理解:

相关文章
相关标签/搜索