AboutFE
AboutFE copied to clipboard
32、各个跨端方案的比较、跨端的问题答疑
http://www.52im.net/thread-1870-1-1.html http://www.52im.net/thread-2641-1-1.html
Flutter
- Flutter 在各个原生的平台中,使用自己的 C++的引擎渲染界面,没有使用 webview,也不像 RN、NativeScript 一样使用系统的组件。简单来说平台只是给 Flutter 提供一个画布。
- 界面使用 Dart 语言开发,貌似唯一支持 JIT,和 AOT 模式的强类型语言。
- 写法非常的现代,声明式,组件化,Composition > inheritance,响应式……就是现在前端流行的这一套
- 一套代码搞定所有平台, 端的一致性。
Flutter 为什么快?Flutter 相比 RN 的优势在哪里?
- Skia 引擎,软件层渲染,RN底下是原生的,有可能使用OPENGL硬件层渲染,Chrome, Chrome OS,Android,Firefox,Firefox OS 都以此作为渲染引擎。
- Dart 语言可以 AOT 编译成 ARM Code,让布局以及业务代码运行的最快,而且 Dart 的 GC 针对 Flutter 频繁销毁创建 Widget 做了专门的优化。
- CSS 的子集 Flex like 的布局方式,保留强大表现能力的同时,也保留了性能。
- Flutter 业务书写的 Widget 在渲染之前 diff 转化成 Render Object,对,就像 React 中的 Virtual DOM,以此来确保开发体验和性能。
- RN 使用 JavaScript 来运行业务代码,然后 JS Bridge 的方式调用平台相关组件,性能比有损失,甚至平台不同 js 引擎都不一样。
- RN 使用平台组件,行为一致性会有打折,或者说,开发者需要处理更多平台相关的问题
闲鱼 flutter 和 rn 性能测试 https://www.yuque.com/xytech/flutter/gs3pnk
Q: 小程序诞生的背景,小程序架构是什么样的,性能为什么好,微信小程序,支付宝小程序有什么区别
1:诞生背景: 早在微信小程序之前,有力推轻应用的百度,有来自 HTML5 中国产业联盟的 DCloud 所主张的流应用,小程序不是一天发展起来的,07年H5和iPhone同年立项,H5推翻了IE+Flash,却没有达到承载优秀的移动互联网体验的地步, iPhone站稳脚跟后跟上APP STORE的开发,安卓也异军突起,于是:在移动互联网初期,应用生态被定了基调 —— 原生开发。在那个时候,硬件不行,也没有其他办法,原生开发才能在低配硬件上带来商用体验。但大家都在怀念 H5,那种无需安装更新、即点即用,直达二级页面的动态发布。 国内有一批做浏览器的厂商,尝试去改进 HTML5,他们提出了轻应用的概念。通过给 WebView 扩展原生能力,补充 JS API,让 HTML5 应用可以实现更多功能。不过这类业务没有取得成功,HTML5 的问题不止是功能不足,性能体验是它更严重的问题。
微信的 JS SDK,为它的浏览器内核扩充了大量 JS API,砍掉较多复杂的初始化损耗,定制化,让开发者可以用 JS 调用微信支付、扫码等众多 HTML5 做不到的功能。(但是引用了后仍旧 存留首页白屏载入问题),于是需结合Hybrid应用 Client/Server模式和HTML5的动态性(流应用概念:把之前 Hybrid 应用里的运行于客户端的 JS 代码,先打包发布到服务器,制定流式加载协议,手机端引擎动态下载这些 JS 代码到本地,并且为了第一次加载速度更快,实现了应用的边下载边运行), 后来这套应用号模式 就改为 小程序。
模式 (技术标准 -> 基础平台 -> 开发工具 -> 培训市场 -> 框架诞生 -> 周边生态逐步完善 -> 轮子之上的轮子)
2: 架构
- 不选RN的原因
- RN 所支持的样式是 CSS 的子集,会满足不了 Web 开发者日渐增长的需求,而对 RN 的改造具有不小的成本和风险。
- RN 现有能力下还存在的一些不稳定问题,比如性能、Bug等。RN 是把渲染工作全都交由客户端原生渲染,实际上一些简单的界面元素使用 Web 技术渲染完全能胜任,并且非常稳定。
- RN 存在一些不可预期的因素,比如之前出现的许可协议问题
- 渲染和逻辑 (纯web,复杂交互因为UI渲染和JS线程在同一个线程,造成抢占式性能损耗) (纯Native,由于字节码问题动态发布不好保证) (取长补短, 于是采用介于客户端原生技术与 Web 技术之间的,互相结合各自特点的技术来渲染)
从渲染底层来看,PhoneGap与微信 JS-SDK 是类似的,它们最终都还是使用浏览器内核来渲染界面。而 RN 则不同,虽然是用 Web 相关技术来编写,同样是利用了 JavaScript 解释执行的特性,但 RN 在渲染底层是用客户端原生渲染的。选择类似微信 JSSDK 这样的 Hybrid 技术,即界面主要由成熟的 Web 技术渲染,辅之以大量的接口提供丰富的客户端原生能力。同时,每个小程序页面都是用不同的WebView去渲染,如复杂的地图视频,同层渲染,这样可以提供更好的交互体验,更贴近原生体验,也避免了单个WebView的任务过于繁重。在原生则是往 WebView 的 window 对象注入一个原生方法,最终会封装成 WeiXinJSBridge 这样一个兼容(胶水)层,主要提供了调用(invoke)和监听(on)这两种方法。开发者插入一个原生组件,一般而言,组件运行的时候被插入到 DOM 树中,会调用客户端接口,通知客户端在哪个位置渲染一块原生界面。在后续开发者更新组件属性时,同样地,也会调用客户端提供的更新接口来更新原生界面的某些部分。
JS SDK,小程序双线程部分 渲染和逻辑分离,单纯的JS执行环境, 通过对于其中的控件也进行了自定义。因此完全采用这个沙箱环境不能有任何浏览器相关接口,只提供纯JavaScript 的解释执行环境,多 WebView 的架构, 每一个小程序页面都是不同的WebView 渲染后显示的(所以serviceWorker这种就不适用), 在iOS下是用内置的 JavaScriptCore框架,在安卓则是用腾讯x5内核提供的JsCore环境, 我们可以创建一个单独的线程去执行 JavaScript,在这个环境下执行的都是有关小程序业务逻辑的代码(逻辑层 - JS 脚本),而界面渲染相关的任务全都在WebView线程里执行,通过逻辑层代码去控制渲染哪些界面(渲染层 - WXML 模板->JS对象和 WXSS 样式)
-
通信 小程序是基于双线程模型,那就意味着任何数据传递都是线程间的通信,也就是都会有一定的延时。这不像传统Web那样,当界面需要更新时,通过调用更新接口UI就会同步地渲染出来。在小程序架构里,这一切都会变成异步。 异步会使得各部分的运行时序变得复杂一些。比如在渲染首屏的时候,逻辑层与渲染层会同时开始初始化工作,但是渲染层需要有逻辑层的数据才能把界面渲染出来,如果渲染层初始化工作较快完成,就要等逻辑层的指令才能进行下一步工作。因此逻辑层与渲染层需要有一定的机制保证时序正确,通过Json的方式进行数据的传递,提高性能的方式就是减少交互的数据量,和RN比通信成本小,只是在Native过了一层不需要和native渲染太多通信。
-
缓存 不同小程序的本地缓存空间是分开的,每个小程序的缓存空间上限为10MB,如果当前缓存已经达到10MB,再通过wx.setStorage写入缓存会触发fail回调。还针对用户进行缓存,保证隐私问题
- 支付宝小程序不同点
-
可配,支付宝小程序不仅提供 JavaScript+Webview 的方式,还提供 JavaScript+Native 的方式,在对性能要求较高的场景,可以选择 Native 的渲染模式,给用户更好的体验
-
支付宝小程序虚拟机隔离(通常的做法是在 WebView 里面运行 render 的代码,然后另起一个线程运行 serviceworker,当 serviceworker 需要更新 dom 的时候把事件和数据通过 messagechannel 发送给 render 线程来执行,当业务需要传递到 render 层数据量较大,对象较复杂时,交互的性能就会比较差,因此针对这种情况支付宝提出一个优化的解决方案。该方案将原始的 JS 虚拟机实例 (即 Isolate) 重新设计成了两个部分:Global Runtime 存放共享的装置和数据,全局一个实例 和 Local Runtime 存放实例自身相关的模块和私有数据,这些不会被共享, setData 对象的会直接创建在 Shared Heap 里面,因此 render 层的 Local Runtime 可以直接读到该对象,并且用于 render 层的渲染,减少了对象的序列化和网络传输,极大的提升了启动性能和渲染性能。)
-
支付宝采用的是 UC 提供的浏览器内核,UC 的同学在浏览器内核的性能、稳定性和兼容性上做了大量的工作,比系统提供的 webview 提升了不少。(稳定性:crash 率只有系统 webview 的三分之一到五分之一;兼容性:不存在各种系统 webview 上的兼容性问题;性能:针对内核启动逻辑,v8 引擎 codecache 深度优化,使得 js 代码解析和编译的时间减少 40% 左右;工具:提供了丰富的工具保障 UC 内核的稳定性和性能)
-
支付宝更考虑兼容性,微信政务的都大部分在公众号上 小程序偏少
[小程序比较](https://zhaomenghuan.js.org/blog/what-is-emp.html
RN 启动和渲染流程,有哪些问题,如何优化,和 weex 有什么区别
重构即将完成!2020版React Native会有多大改善
- 用户点击App的图标
- UIManager线程:加载所有的Native库和Native组件比如 Text、Button、Image等
- 告诉Js线程,Native部分准备好了,Js侧开始加载main.bundle.js,这里面包含了所有的js和react逻辑以及组件。
- Js侧通过Bridge发送一条JSON消息到Native侧,告诉Native怎么创建UI。值得一提的是:所有经过Bridge的通信都是异步的,并且是打包发送的。这是为了避免阻塞UI
- Shadow线程最先拿到消息,然后创建UI树
- 它使用Yoga布局引擎去获取所有基于flex样式的布局,并且转化成Native的布局,宽、高、间距等。
- UIManager执行一些操作并且像这样在屏幕上展示UI
当前架构的缺点是:
- 有两个不同的领域:JS和Native,他们彼此之间并不能真正互相感知,并且也不能共享相同的内存。
- 它们之间的通信是基于Bridge的异步通信。但是这也意味着,并不能保证数据100%并及时地到达另一侧。组件和 API 太过依赖 JSBridge 的初始化,而且通讯能力也局限于这一条通道。
- 传输大数据非常慢,因为内存不能共享,所有在js和native之间传输的数据都是一次新的复制, 使用桥接器可以连接JS线程和原生线程,在后台,C++模块围绕一个异步队列messageQuene构建。每当它从任一方获取数据时,都会将数据序列化为字符串并将其通过队列传递,并在到达时反序列化。这意味着所有线程都依赖于跨网桥传输的异步JSON消息,并且这些消息发送到任一端,期望它们在将来的某个时间引发响应,但它还存在拥塞的风险。
- 同样,布局设计需要经过很多次才能在屏幕上显示,因为在原生设计布局之前,它需要想尽办法到达Yoga引擎,当然这也意味着要通过桥接器, 无法同步更新UI。比方说有个FlatList,当我滑动的时候会加载大量的数据。在某些边界场景,当有用户界面交互,但数据还没有返回,屏幕可能会发生闪烁。
- RN代码仓库太大了。导致库更重,开源社区贡献代码或发布修复也更慢。
新架构优化
RN 在 0.59 版本使用 JSI 取代了先前的 JSBridge 0.60.2 以上的版本, fb 推出了新一代JavaScript执行引擎Hermes 采用JS标准,只需enableHermes Hermes 即可缩短启动时间、减少内存使用量并缩小应用程序大小,专门针对在 Android 上运行优化。
JSI是架起 JS 和Native之间的桥梁,通过在C++层实现一个 JSI::HostObject,现在不需要序列化成JSON并双向传递等一系列操作,实现了Native和 JS间的直接同步通讯, 通过使用JSI,Fabric将UI操作作为函数公开给JavaScript,新的Shadow Tree(决定在屏幕上真正显示的内容)在两个领域之间共享,允许两端直接交互。它抹平了 JavaScript 引擎的差异。使用 JSI,我们不必关心底层是Hermes 引擎还是 JavaScriptCore 引擎,JSI 底层都消化了。因此只需要基于 JSI 的接口编写即可
使用新架构,App启动的流程是这样的。
- 用户点击App的图标
- Fabric加载Native侧(没有Native组件, Turbo Modules 懒加载)
- 然后通知JS线程Native侧准备好了,JS侧会加载所有的main.bundle.js,里面包含了所有的js和react逻辑+组件
- JS通过一个Native函数的引用(JSI API导出的)调用到Fabric,同时Shadow Node创建一个和以前一样的UI树。
- Yoga执行布局计算,把基于Flexbox的布局转化成终端的布局。
- Fabric执行操作并且显示UI
为了完成整个流程,我们几乎做了同样的事情,
- 但是没有了Bridge,现在我们可以有更好的性能,我们可以用同步的方式进行操作,甚至可以对UI上的同步操作进行优先级排序。启动时间也将更快,App也将更小。
- JSC引擎与其他(可能更高性能的)JavaScript引擎互换,例如V8。
- 这种新架构还可以直接控制原生模块。这意味着我们可以在需要时使用原生模块,而不是在启动时将它们全部引导一次。这大大提高了性能,节省了启动时间
滑动白屏问题
- 原来: 因为 JSBridge 的异步关系导致了 shadow 层最终呈现到原生的 UI 是异步的,而且滑动太快后会有大量的 UI 事件会阻塞在 JSBridge
新架构后
- 初始化:JS 到 Shadow 层已经是同步操作了,而 shadow 层到原生 UI 变成了可以异步也可以同步操作了,组件可以根据自己的业务场景来适配不同的操作。
- 滑动过程:原生端直接控制 JS 层渲染,同时创建 shadow 层的 node 节点,node 节点会采用同步的方式渲染原生 UI,整个过程中滑动的渲染是采用的同步操作,所以不会出现旧架构下白屏的问题
weex 最大的优势可以在不支持某些组件的情况下降级成h5渲染【手淘】
webview 的内核有哪些,webview 有哪些问题,如何优化,jsBridge 怎么实现,怎么优化
-
内核 iOS 不允许有第三方内核,iOS2~7:UIWebView;iOS8:WKWebView Andorid 每个版本都自带了浏览器内核,要么是chromium要么是很老的webkit。而微信是自己带的一个改造版的chromium(Blink X5, 同理支付宝UC内核也是,我们也可以自己去外网拉内核过来做修改)。苹果是用的自己的新版webkit
-
问题。可讲小程序纯web渲染的缺点,优化围绕小程序趋势,跨端趋势
-
优化(白屏到秒开,做离线化,提前找时机如天猫游戏等预加载,去远程拉取资源打到容器内)
jsBridge
JavaScript 调用 Native 推荐使用 注入 API 的方式,Native 调用 JavaScript 则直接执行拼接好的 JavaScript 代码即可,最终演化为一个 BridgeName 对应一个 Native 功能或者一类 Native 消息 (对于接受消息&&回调):用一个自增的唯一 id,来标识并存储回调函数,并把此 id 以参数形式传递给 Native,而 Native 也以此 id 作为回溯的标识。这样,即可实现 Callback 回调逻辑。
https://github.com/CodingMeUp/AboutFE/issues/32#issuecomment-633236106,
- jsbridge优化点
- 通信(是 Native 和非 Native 之间的桥梁,它的核心是 构建 Native 和非 Native 间消息通信的通道,而且是 双向通信的通道。存在单线程阻塞问题,安卓可用智能代理,通信时候可返回信号值,如游戏是native实时来调,电商就有Webview页面调用)
- 注入时期(防止恶意攻击,有注入安全机制,如低版本 频率太快,就会认定为攻击,或者在某段时间内,线程不让出,死锁状态也没法注入,IOS 安卓都是99%注入成功,)
跨端怎么跨,思路,实现
从前端两大职责,UI 和 交互逻辑来讲 也可以说从上往下讲,需要 跨端 DSL,跨端组件,跨端容器(容器 api),跨端渲染引擎
- 跨端 DSL 很好理解,就是自建一套 DSL 用来做视图层的描述,这套 DSL 最后还是生成 ast
- 跨端组件,比如 h5 的 div ,小程序的 View,native 的 View
- 跨端 api 比如 h5 的 fetch,小程序的 request,native 的 httpClient
- 跨端渲染引擎,比如 flutter 就自建了渲染引擎用来适配不同端是比较彻底的跨端渲染引擎,像 RN 其实还是用的各个端自己的渲染引擎,只是把部分 html 和 css 的规范实现了,比如用 yoga 来跨端实现部分 css,这种算是加了一层适配层来实现跨端的渲染
- 其实还有跨端的交互逻辑,这个比较无解,几乎所有的端都是另开线程去执行 js,然后和不同端去通信。除了 flutter 是自己用 dart 去做逻辑,底层事件手势全都自己接管了。
以上所有的点都可以从实现方式的好处和缺点,有哪些性能问题,社区都如何解决来了解
eg: flutter的渲染引擎是?
Flutter是由Google推出的开源的高性能跨平台框架,一个2D渲染引擎。在Flutter中,Widget是Flutter用户界面的基本构成单元,可以说一切皆Widget。 它通过自绘 UI ,解决了之前 RN 和 weex 方案难以解决的多端一致性问题。Dart AOT 和精减的渲染管线,相对与 JavaScript 和 webview 的组合,具备更高的性能体验。
渲染流水线
其中 1-6 在收到系统 vsync 信号后,在 UI 线程中执行,主要是涉及在 Dart framework 中 Widget/Element/RenderObject 三颗树的生成以及承载绘制指令的 LayerTree 的创建,7-8 在 GPU 线程中执行,主要涉及光栅化合成上屏。 1-4跟渲染没有直接关系,主要就是管理UI组件生命周期,页面结构以及Flex layout等相关实现,本文不作深入分析。 5-8为渲染相关流程,其中5-6在UI线程中执行,产物为包含了渲染指令的Layer tree,在Dart层生成,可以认为是整个渲染流程的前半部,属于生产者角色。 7-8把dart层生成的Layer Tree,通过window透传到Flutter engine的C++代码中,通过flow模块来实现光栅化并合成输出。可以认为是整个渲染流程的后半部,属于消费者角色
- Framework层 纯 Dart实现的 SDK,类似于 React在 JavaScript中的作用。它实现了一套基础库, 用于处理动画、绘图和手势。并且基于绘图封装了一套 UI组件库,然后根据 Material 和Cupertino两种视觉风格区分开来。
- Engine层 纯 C++实现的 SDK,其中包括 Skia引擎、Dart运行时、文字排版引擎等。它是 Dart的一个运行时,它可以以 JIT 或者 AOT的模式运行 Dart代码。这个运行时还控制着 VSync信号(显示器每秒发出60次绘图的信号)的传递、GPU数据的填充等,并且还负责把客户端的事件传递到运行时中的代码。
从上图可知Flutter Engine中的一些绘图原理,Flutter渲染UI的本质就是在VSync信号中快速构建并提供抽象的视图结构数据,所以Flutter的精髓在Flutter Dart Framework里,这里涉及了很多优秀的设计思想、优化策略
eg: flutter 的线程模型
从渲染引擎的视角来看,Flutter 的四个线程的职责如下:
- Platform 线程:负责提供Native窗口,作为GPU渲染的目标。接受平台的VSync信号并发送到UI线程,驱动渲染管线运行。
- UI 线程:负责UI组件管理,维护3颗树,Dart VM管理,UI渲染指令生成。同时负责把承载渲染指令的LayerTree提交给GPU线程去光栅化。
- GPU线程:通过flow模块完成光栅化,并调用底层渲染API(opengl/vulkan/meta),合成并输出到屏幕。
- IO 线程:包括若干worker线程会去请求图片资源并完成图片解码,之后在 IO 线程中生成纹理并上传 GPU ,由于通过和 GPU 线程共享 EGL Context,在 GPU 线程中可以直接使用 IO 线程上传的纹理,通过并行化,提高渲染的性能
https://www.zhihu.com/search?type=content&q=flutter%E6%B8%B2%E6%9F%93%E5%BC%95%E6%93%8E
eg: 在Android和IOS双端快速去构建一个差异化高效的渲染链路。目前双端主要以web作为跨平台渲染的主要形式下,提供了一个更容易定制和优化的方案
基于Flutter engine,我们去除了原生的dart引擎,引入js引擎,用C++重写了Flutter Framework中的rendering,painting以及widget的核心逻辑,继续向上封装基础组件,实现cssom以及C++版的响应式框架,对外提供统一的JS Binding API,再向上对接小程序的DSL,供小程序业务方使用。对于性能要求比较高的小程序,可以选择使用这条链路进行渲染
受限于小程序worker/render的架构,互动业务中频繁的绘制操作需要经过序列化/反序列化并把消息从worker发送到render去执行渲染命令。基于flutter engine,我们提供了一套独立的2d渲染引擎,引入canvas的渲染管线,提供标准的canvas API供业务直接在worker线程中使用,缩短渲染链路,提高性能。目前已经支持了相关的互动业务在线上运行,性能和稳定性表现很好
跨端的发展历史
先聊前端,前端是干嘛的 “前”是指离用户最近,“端”是指端侧。前端就是离用户最近,需要在用户端里实现产品需求并且能给用户尽可能好的用户体验
为什么要跨端,用户可能从很多不同的入口进来,我们无法强制用户端,就只能尽可能在所有端里面满足用户的需求,给用户尽可能好的体验,准确的说“中心和跨端是沉淀出来的,而不是规划出来的,像中台一样,每个企业的IT系统应该根据自己的业务价值沉淀符合业务需要的共享服务中心
- pc 时代的跨浏览器兼容
- 无线时代的 webview 支持
- rn,weex 的出现
- 小程序, PWA
- flutter
在以上的阶段,都可以从背景,问题,解决方案,遗留或者无法解决的问题来聊
RN跨端路由的改造
- 原来在一个native view上叠 多层前端页面(为啥要前端自己做路由 1,拓展生命周期, 2那时候没有比较好的路由库) 性能问题 底下如果有地图
- 改为 1个页面 native生成一个rctView来做,提高体验 ,并且可支持跳转native页面,后续可配合拆包 和 发布平台 做动态下发
- 改造的同时 类似水印这种复杂情况生成就下沉到 native去渲染 就不需要每个react页面去生成一个
RN link 原理
1, 去执行rnpm 且 Rnpm是写在SDK 的 package.json里 2, 就是把native的东西放到native目录底下
RN 通信
- JS和OC的通信
“普通的JS-OC通信实际上很简单,OC向JS传信息有现成的接口,像webview提供的-stringByEvaluatingJavaScriptFromString方法可以直接在当前context上执行一段JS脚本,并且可以获取执行后的返回值,这个返回值就相当于JS向OC传递信息。React Native也是以此为基础,通过各种手段,实现了在OC定义一个模块方法,JS可以直接调用这个模块方法并还可以无缝衔接回调。”
“JS函数调用转ModuleID/MethodID -> callback转CallbackID -> OC根据ID拿到方法 -> 处理参数 -> 调用OC方法 -> 回调CallbackID -> JS通过CallbackID拿到callback执行”
- JS和Java的通信
传统的JS 调用 Java方法(Jsbridge、onprompt、log 及 addjavascriptinterface等)RN 中并没有采用,而是借助 MessageQueue 及模块配置表,将调用转化为{moduleID, methodID,callbackID,args},处理端在模块配置表里查找注册的模块与方法并调用, RCTDeviceEventEmitter的emit方法是一个虚方法, 实际是被动态代理了。最终执行者是 JavaScriptModuleInvocationHandler 的 invoke方法里的PendingJSFunction对象的jniCallJS()
在调用条件上,OC/JAVA在调用JS是可以通过JS暴露的接口,在使用模块配置表转化后直接调用的,而JS调用OC/JAVA则是通过事件触发。
https://www.jianshu.com/p/5b5854187aa2
RN的回调以及线程模型小结
回调
- JS 与 Native 间传递的是 callbackID;
- callback 参数只能位于方法参数列表的最后面并且最多只能有2个;
- RN 通过 callbackID 二进制的最后一位是0还是1,确定是 success 还是 fail;
- 由于 JS callback function 无法直接传递给 Native,Native 侧会生成一个 block。
三个线程
-
JS Thread【JS Thread 是 JS 执行以及 JS 与 Native 通信线程。 简单讲,Native 在此线程执行 JS 代码,JS 调用 Native 接口也发生在此线程上。 JS Thread 的初始化发生在RCTCxxBridge#start方法中】
-
Native Module Thread【JS 在调用 Native 方法时,Native 方法这个线程上执行】
-
UI Manager Thread(Shadow Thread) 【UI Manager Thread,UI 组件(UI module)接口执行线程,是一个高优先级的串行队列。 UI 不在主线程, RN 为了提高效率(如: 帧率),会先在UI Manager Thread做一些预处理操作(如计算 frame),最终在渲染上屏时会切到 main thread】
所有 JS 代码都会在独立线程 JSThread 上执行; 可通过 methodQueue 方法自定义 Native module 执行线程; 为了提高效率,所有 UI 组件都会在 UI Manager thread 上预处理,再在 main thread 上渲染上屏。
rax 相关 http://rax.alibaba-inc.com/
https://fed.taobao.org/blog/taofed/do71ct/why-rax/?spm=ata.13261165.0.0.4b0460d04Tjqkc
https://zhuanlan.zhihu.com/p/100198414