当前位置: 首页 > 科技观察

详细了解ReactNative的新架构

时间:2023-03-20 01:08:55 科技观察

ReactNative团队宣布新架构将于2022年推出。点击此处[1]查看他们的完整博客。"2022isgoingtobetheyearoftheNewArchitectureinopensource"(2022将是开源新架构之年)既然新版本即将到来,现在是了解发生了哪些变化的好机会在它的底部,以及这些变化会对我们的ReactNativeApp产生什么影响本文主要介绍本次重构变化最大的部分:JavaScriptInterface(JSI)FabricTurboModulesCodeGenCurrentArchitecture在学习新架构之前,让我们回顾一下当前的架构。这次我只罗列一些与本文相关的知识点。如果你想了解更多关于当前架构的信息,请阅读BiancaDragomir的这篇文章[2]简而言之:当我们运行RN应用程序时,所有的javascript代码都会被打包到JSBundle中,而Native代码会单独保存。RN有以下三个线程:JS线程:JS引擎使用这个线程来运行JSBundle。Native/UI线程:运行原生能力(NativeModules),处理UI渲染,用户手势事件等操作。shadowthread:在元素渲染之前计算布局。JS和Native线程通过桥进行通信。通过网桥发送数据时,网桥会将数据排队进行批处理(优化)并序列化成JSON,通信只能是异步的。当前重要术语:JavaScriptCore:JavaScript引擎,用于执行JS代码。Yoga:UI引擎,用于计算元素在用户屏幕上显示的位置。1、在目前的JavaScriptInterface(JSI)框架中,JS和Native线程通过一个桥梁进行通信。每次传输数据时,都需要先将数据序列化为JSON,接收时再解析回来。这意味着JS和Native是相互独立的。(JS线程不能直接调用Native线程的方法)还有一点需要注意的是bridge传输的数据本质上是异步的,大部分用例是没有问题的,但是在某些情况下,我们也需要JS和native代码同步执行。例如:当一个JS线程需要使用一个native模块(如:蓝牙)时,需要向Native线程发送信息。首先,JS线程会发送一个序列化的JSON数据给bridge,然后bridge将数据优化后发送给Native线程,Native线程解析JSON数据,最终运行需要的native代码。bridge1)JS线程准备数据2)将数据序列化为JSON再发送给bridge3)在bridge传输的另一端解析数据4)Native线程执行需要的native代码但是在新的架构中,bridge将被JavaScriptInterface取代,这意味着它是一个用C++编写的轻量级通用层,JS引擎可以用它直接调用native方法。什么是泛型?目前的架构使用的是JavaScriptCore引擎,桥只兼容这个引擎。JSI则不然,它把JavaScript接口和引擎解耦了,也就是说新的架构可以使用其他的JavaScript引擎,比如Chakra、v8、Hermes等,所以是“通用的”。JSI是如何让JavaScript直接调用native方法的呢?在JSI中,本地方法通过C++宿主对象暴露给JavaScript。JavaScript会保存对这些对象的引用,并通过这些引用直接调用方法。与Web类似,JavaScript保留对DOM元素对象的引用并调用它们的方法。例如:constcontainer=document.createElement('div');在此代码中,JavaScript变量容器指向DOM元素的引用,该元素可能由C++初始化。当我们调用容器的任何方法时,容器都会调用DOM元素内部的方法。JSI以类似的方式工作。与bridge不同的是,JSI允许JavaScript保存对NativeModules的引用,JavaScript可以通过JSI直接调用引用的方法。jsi1)JavaScript持有对本机模块的引用1)它通过JavaScript接口调用本机模块的方法。.以后不再需要将数据序列化成JSON,同时避免桥接阻塞和异步问题。JSI的另一大优势是它是用C++编写的,借助C++,ReactNative可以运行在大量的系统中,比如智能电视、智能手表等。2.FabricFabric是一个渲染系统,将取代当前的UI管理器。为了了解Fabric的优势,我们先来看看ReactNative目前是如何渲染UI的:应用运行时,React执行代码,在JavaScript中创建ReactElementTree,Renderer基于它在C++中创建ReactShadowTree。布局引擎根据虚拟树计算UI元素在屏幕上的位置。计算完成后,虚拟树将转换为由NativeElements组成的HostViewTree。*(例子:ReactNative中的Elements在Android和iOS中分别转换为ViewGroup和UIView)*fabricReactElementTree(JavaScript)->ReactShadowTree(C++)->HostViewTree(Native)这种方法的问题:正如我们所知,线程间相互通信是通过网桥实现的,这意味着传输速率低和不必要的数据复制。例如:ReactElementTree中的一个节点也是ReactShadowTree中的一个图像,但是必须在两个节点中复制两份数据。而且,由于JS和UI的线程不同步,在某些情况下甚至会出现丢帧卡顿的情况。(例如:滚动包含大量数据的FlatList)什么是Fabric?根据ReactNative的官方文档[3],“FabricisReactNative'snewrenderingsystem,aconceptualevolutionofthelegacyrendersystem”(FabricisReactNative'snewrenderingsystem,itsconceptevolvedfromthetraditionalrenderingsystem)如我们所见在本文的JSI部分,JSI将native方法直接暴露给JavaScript,其中也包括UI方法,从而让JS和UI线程同步,从而提高了列表、导航、手势处理等性能,会有什么好处面料带?在新的渲染系统中,滚动和用户手势等用户交互可以先在主线程或原生线程中同步执行,而其他任务,如界面请求,将异步执行。此外,新的ShadowTree是不可变的,并且树在JS和UI线程之间共享,以允许来自两端的直接交互。在其当前架构中,ReactNative必须维护两个层次结构/DOM节点。在新的架构中,只需要维护shadowtree,线程间共享,也有助于减少内存消耗。3.TurboModules在目前的架构中,所有JavaScript使用的原生模块(如蓝牙、地理位置、文件存储等)都必须在应用打开前进行初始化。这意味着即使用户不需要一个模块,它仍然会在启动时被初始化。TurboModules基本上是对旧的NativeModules的增强。正如我们上面看到的,JavaScript现在可以保留对这些模块的引用,这使得我们的JS可以按需加载模块,大大提高了ReactNative应用程序的启动速度。4.CodeGenFabric和TurboModules听起来很有前途,但是JavaScript是动态语言,而JSI是用C++写的,而C++是静态语言,所以需要保证两者之间的顺畅通信。这就是为什么新架构还包括一个名为CodeGen的静态类型检查器。CodeGen使用类型化JavaScript来定义供Turbo模块和Fabric使用的接口元素,它在构建时生成的本机代码比运行时多。综上所述,所有的变化结合起来,新的架构如图:new主要亮点是:Bridge将被JSI取代,JavaScriptCore可以被其他引擎取代,所有线程可以完全互操作。Web风格的渲染系统可以同步时间敏感的任务。执行TurboModules实现JS端和Native端的模块延迟加载和静态类型检查。我们可以肯定的是,新的架构将给ReactNative带来强大的改进。