# 双线程架构
- 小程序的双线程架构设计。
- 双线程对比单线程的优势在哪里。
- 传统h5开发环境有什么弊端。
- Native层在双线程架构中起到怎样的作用。
- 如何解决传统h5的安全管控问题
目前来说,页面渲染的方式主要有三种:
- Web 渲染。
- Native 原生渲染。
- Web 与 Native 两者掺杂,也即我们常说的 Hybrid 渲染。
前面也说过,小程序最终的呈现形式,是 WebView + 原生组件,Hybrid 方式。我们结合之前对小程序的期望来看:
- 开发门槛:Web 门槛低,不过 Native 也有像 RN 这样的框架支持
- 体验:Native 体验比 Web 不要好太多,Hybrid 在一定程度上比 Web 接近原生体验
- 版本更新:Web 支持在线更新,Native 则需要打包到微信一起审核发布
- 管控和安全:Web 可跳转或是改变页面内容,存在一些不可控因素和安全风险
由于小程序的宿主是微信,如果用纯客户端原生技术来编写小程序 ,那小程序代码需要与微信代码一起编包,跟随微信发版本,这种方式跟开发节奏必然都是不对的。 所以方向应该是需要像 Web 技术那样,有一份随时可更新的资源包放在云端,通过下载到本地,动态执行后即可渲染出界面。
但是如果用纯 Web 技术来渲染小程序,在一些有复杂交互的页面上可能会面临一些性能问题。 这是因为在 Web 技术中,UI 渲染跟 JavaScript 的脚本执行都在一个单线程中执行,这就容易导致一些逻辑任务抢占 UI 渲染的资源。
最终,小程序技术选型 - 选择类似于微信 JSSDK 这样的 Hybrid 技术,即界面主要由成熟的 Web 技术渲染,辅之以大量的接口提供丰富的客户端原生能力。同时,每个小程序页面都是用不同的WebView去渲染,这样可以提供更好的交互体验,更贴近原生体验,也避免了单个 WebView 的任务过于繁重。此外,界面渲染这一块我们定义了一套内置组件以统一体验,并且提供一些基础和通用的能力,进一步降低开发者的学习门槛。值得一提的是,内置组件有一部分较复杂组件是用客户端原生渲染的,以提供更好的性能。
总地看来,小程序选择了 Hybrid 的渲染方式,可以用一种近似 Web 的方式来开发,并且还可以实现在线更新代码。同时,引入原生组件有以下好处:
- 扩展 Web 的能力。比如像输入框组件(input, textarea)有更好地控制键盘的能力
- 体验更好,同时也减轻 WebView 的渲染工作
- 绕过 setData、数据通信和重渲染流程,使渲染性能更好
现在,我们还剩下一个很重要的问题:管控性和安全性。于是,双线程的设计被提出来了。
# 双线程设计
小程序的架构模型有别与传统 web 单线程架构,小程序为双线程架构。微信小程序的渲染层与逻辑层分别由两个线程管理,渲染层的界面使用 webview
进行渲染;逻辑层采用 JSCore
运行JavaScript
代码。这里先看一下小程序的架构图:
从图中看出,由于渲染层与逻辑层分开,一个小程序有多个界面,所以渲染层对应存在多个webview
。这两个线程之间由Native
层进行统一处理。无论是线程之间的通讯、数据的传递、网络请求都由 Native 层做转发。
- 逻辑层:创建一个单独的线程去执行 JavaScript,在这个环境下执行的都是有关小程序业务逻辑的代码;
- 渲染层:界面渲染相关的任务全都在 WebView 线程里执行,通过逻辑层代码去控制渲染哪些界面。一个小程序存在多个界面,所以渲染层存在多个 WebView 线程;
- 通信:这两个线程的通信会经由微信客户端(Native)做中转,逻辑层发送网络请求也经由 Native 转发。
JS 逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的 DOM API 和 BOM API,无法操作页面元素,能达到管控的目的,但也限制了开发者的权限:
- 不允许开发者把页面跳转到其他在线网页
- 不允许开发者直接访问 DOM
- 不允许开发者随意使用 window 上的某些未知的可能有危险的 API
这样的逻辑层与 UI 层的隔离,加上小程序的审核和举报机制,使得微信加强对小程序的管控
webview
平常我们浏览网页都是在浏览器中,可以想象webview
是一个嵌入式的浏览器,是嵌入在原生应用中的。webview
用来展示网页的 view
组件,该组件是你运行自己的浏览器或者在你的线程中展示线上内容的基础。使用 webkit
渲染引擎来展示,并且支持前进后退、浏览历史、放大缩小、等更多功能。
简单来说 webview
是手机中内置了一款高性能 webkit
内核浏览器,在 SDK 中封装的一个组件。不过没有提供地址栏和导航栏,只是单纯的展示一个网页界面。iframe
为页面中嵌入页面的方式,有别于webview
嵌入原生应用的概念。
# 为什么要做多个webview
为了更加接近原生应用APP的用户体验。多个webview
可以理解为多页面应用,有别于单页面应用SPA
,SPA
渲染页面是通过路由识别随后动态将页面挂载到root
节点中去,如果单页面应用打开一个新的页面,需要先卸载掉当前页面结构,并且重新渲染。很显然原生APP并不是这个样子,比较明显的特征为从页面右侧向左划入一个新的页面,并且我们可以同时看到两个页面。多页面应用就很好达到这个效果,新页面直接滑动出来并且覆盖在旧页面上即可,这也是小程序现在所做的形式。这样的用户体验是非常好的。
# 单线程阻塞静态资源问题
因为html
文件是从上到下渲染的,如果中间插入js
的话,则会中断HTML
节点渲染,转而去执行js
,js
执行完后继续渲染节点。就是因为单线程阻塞问题才建议在下方插入script
,并且配合window.onload
可以拿到已经渲染完成的节点。
这种情况当然也可以通过一些手段来规避,比如async
、defer
等。这两个属性加上后,虽然不会阻塞DOM
渲染,但是并不是根本上解决问题,而是合理地安排了资源解析而已。
单线程阻塞问题还没结束,另一个问题又扑面而来。如果所有资源都是通过请求来获取,那么不光会阻塞 js 解析的时间,还要加上 js 请求的时长。请求 js 资源时间不可控,怎么办呢?这个时候另一种选择就至关重要,就是缓存。
# Native
层动态注入
WXSDK
,微信SDK是一系列jsApi
的集合,提供了微信的丰富原生能力和微信内部的方法。
曾经开发微信公众号 h5 的时候我们需要手动的注入某个版本的微信 SDK 到自身的项目中去,这种方式的用户体验并不是很好,因为加载 js,并且解析 js 逻辑的时候是会抢占渲染资源的,原因也就是上面刚讲过的单线程阻塞问题。如果在我们有承接平台的时候(比如微信客户端),将微信 SDK 这样的资源放在客户端 Native 中,在加载页面的时候再进行动态的注入,由 Native
层注入到视图层。这样做可使包的体积变小,其次,减少了网络请求的发送。
小程序中也用到了微信 SDK,将微信 SDK 通过Native
层注入到双线程中。此外还有底层基础库
、Service
等都是事先放在Native
层中的,当页面进行加载的时候再进行动态的注入。可以看出,双线程的好处不仅仅是一分为二而已,还有强大的Native
层做背后支撑。
Native
层除了做一些资源的动态注入,还负责着很多的事情,请求的转发,离线存储,组件渲染等等。界面主要由成熟的 Web 技术渲染,辅之以大量的接口提供丰富的客户端原生能力。同时,每个小程序页面都是用不同的 WebView 去渲染,这样可以提供更好的交互体验,更贴近原生体验,也避免了单个WebView
的任务过于繁重。此外,界面渲染这一块还定义了一套内置组件以统一体验,并且提供一些基础和通用的能力。内置组件有一部分较复杂组件是用客户端原生渲染的,以提供更好的性能。
# 安全管控问题
基于Web
技术来渲染小程序是存在一些不可控因素和安全风险的。这是因为Web技术是非常开放灵活的,我们可以利用JavaScript
脚本随意地跳转网页或者改变界面上的任意内容。
如果微信小程序可以离线浏览,只需要小程序开发者把一些应用数据缓存到本地,然后通过javascript
脚本把小程序渲染的webview
跳转到其他的在线网页,那么这个体验就非常的糟糕。想必前端开发者会非常熟悉这个操作。除此之外,javascript
还可以通过操作DOM,直接获取小程序内部的一些敏感数据,比如用户的信息,商家信息等等,那么小程序将毫无安全可言。
为了解决安全管控问题,小程序阻止开发者使用一些浏览器提供的比如跳转页面、操作DOM、动态执行脚本的开放性接口。如果这些东西一个一个地去禁用,那么势必会进入一个糟糕的循环,因为javascript
实在是太灵活了,浏览器的接口也太丰富了,很容易就遗漏一些危险的接口,而且就算是禁用掉了所有感觉到危险的接口,也势必防不住浏览器内核的下次更新。指不定又会出现一些漏洞。
# 双线程模型的由来
因此,要彻底解决这个问题,必须提供一个沙箱环境来运行开发者的JavaScript
代码。这个沙箱环境不能有任何浏览器相关接口,只提供纯JavaScript
的解释执行环境,那么像HTML5
中的ServiceWorker
、WebWorker
特性就符合这样的条件,这两者都是启用另一线程来执行 javaScript
。但是考虑到小程序是一个多 webView
的架构,每一个小程序页面都是不同的webView
渲染后显示的,在这个架构下不好去用某个webView
中的ServiceWorker
去管理所有的小程序页面。
得益于客户端系统有javaScript 的解释引擎
(在iOS下使用内置的 javaScriptCore
框架,在安卓则是用腾讯x5内核提供的JsCore
环境),可以创建一个单独的线程去执行 javaScript
,在这个环境下执行的都是有关小程序业务逻辑的代码,也就是我们前面一直提到的逻辑层。而界面渲染相关的任务全都在webview
线程里执行,通过逻辑层代码去控制渲染哪些界面,那么这一层当然就是所谓的渲染层。这就是小程序双线程模型的由来:
- 逻辑层:创建一个单独的线程去执行 JavaScript,在这个环境下执行的都是有关小程序业务逻辑的代码
- 渲染层:界面渲染相关的任务全都在 WebView 线程里执行,通过逻辑层代码去控制渲染哪些界面。一个小程序存在多个界面,所以渲染层存在多个 WebView 线程
# 小程序是期望的产物
使用 WebView 开发,门槛低,可云端更新。
不同于 RN、Weex 这些框架,原生组件的开发、样式调整等都和 Web 有太多的不同。对于一个前端开发来说,开发成本较高、调试效率低,若不小心掉到坑里,都不知道该怎么爬出来。
使用 WebView,可最大化前端开发的优势,同时异步加载的方式,也允许开发者进行在线的版本更新和 BUG 修复。
通过提供基础能力、原生组件结合等方式,提升用户体验。
小程序框架提供了完整的基础库,通过微信内置基础库、双线程渲染等方式,提升了小程序启动的体验。同时,开发者可以借用原生组件、API 等能力,做很多普通页面开发做不到的事情,用户也能以此获得原生应用般的体验。
通过平台发布、审核、下架、封禁等能力,具备对小程序的管控能力。
小程序框架提供了云端更新的能力,通过代码上传、审核等方式,增强了对开发者的管控能力。保护用户的同时,也保护了平台,以及平台中的其他开发者。
双线程(逻辑层和渲染层分开),隔离 DOM、BOM 能力,提升体验的同时,可保证 WebView 安全性。
双线程的模式,使得页面渲染和逻辑代码的加载分开,降低了页面卡壳的可能性。
同时,由于逻辑层被隔离 DOM 和 BOM 对象,无法获取渲染层的内容,也在一定程度上保护了用户的数据安全。
# 双线程通信
通过上述双线程的设计我们知道, JS 逻辑代码放到单独的线程去运行,但在 Webview 线程里,开发者就没法直接操作 DOM。那要怎么去实现动态更改界面呢?
那么在双线程的设计中,**逻辑层和渲染层的通信会由 Native (微信客户端)做中转,逻辑层发送网络请求也经由 Native 转发。**这是不是意味着,我们可以把 DOM 的更新通过简单的数据通信来实现呢?
Virtual DOM 相信大家都已有了解,大概是这么个过程:用 JS 对象模拟 DOM 树 -> 比较两棵虚拟 DOM 树的差异 -> 把差异应用到真正的 DOM 树上。所以双线程的通信原理如下:
- 在渲染层把 WXML 转化成对应的 JS 对象。
- 在逻辑层发生数据变更的时候,通过宿主环境提供的 setData 方法把数据从逻辑层传递到 Native,再转发到渲染层。
- 经过对比前后差异,把差异应用在原来的 DOM 树上,更新界面。
我们通过把 WXML 转化为数据,通过 Native 进行转发,来实现逻辑层和渲染层的交互和通信。而这样完整的一套框架,基本上都是通过小程序的基础库来完成的。
# 小程序的基础库
小程序的基础库是 JavaScript 编写的,它可以被注入到渲染层和逻辑层运行。主要用于:
- 在渲染层,提供各类组件来组建界面的元素
- 在逻辑层,提供各类 API 来处理各种逻辑
- 处理数据绑定、组件系统、事件系统、通信系统等一系列框架逻辑
由于小程序的渲染层和逻辑层是两个线程管理,两个线程各自注入了基础库。**小程序的基础库不会被打包在某个小程序的代码包里边,它会被提前内置在微信客户端。**这样可以:
- 降低业务小程序的代码包大小
- 可以单独修复基础库中的 Bug,无需修改到业务小程序的代码包
小程序的视图是在 WebView 里渲染的,那搭建视图的方式自然就需要用到 HTML 语言。如果我们直接提供 HTML 的能力,那前面章节所介绍的为解决管控与安全而建立的双线程模型就成为摆设了。开发者可以利用A标签实现跳转到其它在线网页,也可以动态执行 JavaScript 等。除管控与安全外,还有一些的不足之处:
标签众多,增加理解成本;
接口底层,不利于快速开发;
能力有限,会限制小程序的表现形式。
因此,我们设计一套组件框架 —— Exparser
。基于这个框架,内置了一套组件,以涵盖小程序的基础功能,便于开发者快速搭建出任何界面。同时也提供了自定义组件的能力,开发者可以自行扩展更多的组件,以实现代码复用。
# Exparser 框架
Exparser
是微信小程序的组件组织框架,内置在小程序基础库中,为小程序的各种组件提供基础的支持。小程序内的所有组件,包括内置组件和自定义组件,都由 Exparser 组织管理。Exparser 特点包括:
- 基于 Shadow DOM 模型:模型上与 WebComponents 的 ShadowDOM 高度相似,但不依赖浏览器的原生支持,也没有其他依赖库;实现时,还针对性地增加了其他 API 以支持小程序组件编程。
- 可在纯 JS 环境中运行:这意味着逻辑层也具有一定的组件树组织能力。
- 高效轻量:性能表现好,在组件实例极多的环境下表现尤其优异,同时代码尺寸也较小。
# 双线程模型的优缺点
优点:
- 将逻辑层和渲染层隔离开,用户无法直接操作
DOM
,提供了相对封闭和安全的运行环境。 - JS 执行不会阻塞或干扰
webView
渲染,但是大部分情况下视觉都要依赖 JS 中处理的数据,JS 如果被阻塞(阻塞原因有逻辑重或请求慢等)了就不会通知视图去更新(即执行setData
),所以这条优点其实意义不是很大!所以小程序官方搞出了 初始渲染缓存 (opens new window),会缓存初始data(不包含setData)的渲染结果。 - 所有的页面和组件的逻辑(js)都在一个线程(
AppService
)里,使用同一个上下文环境,比较好做状态共享或跨页面通讯。
缺点:
每一次数据传递都要进行一次线程之间的通信,业务逻辑跟渲染层天然隔离,造成通信开销大、延迟高等问题,通信越频繁、数据量越大,则性能瓶颈越严重。
每个页面都创建一个
WebView
线程处理,有更多的内存、时间开销。渲染层和逻辑层状态要维护两份,进一步加重内存、时间开销,并且没有办法完全保证两份数据状态实时保持一致,例如仅使用
this.data
更新数据而不是通过setData
时,那么实际渲染的值与逻辑层的值就不一致,某些场景下会造成非预期的问题。
总体上从开发者的角度来看,小程序的双线程模型架构并不是一个很好的架构,逻辑层与渲染层隔离,带来的问题远远比它解决的问题更多。
除了状态共享和跨页面通信外,几乎对开发者来说没啥吸引力,但是依旧很鸡肋:
- 一个应用里面的多个页面,你认为是共享的状态多,还是独立的状态多?
- 用户在操作页面时,更关心跨页面通信效率,还是更关心当前页面的渲染效率(页面里的内容是否顺滑)?
我们当然更关心性能,但是从微信的角度来说,他们想既能享受 web
生态的好处的同时也能限制 web
的开放性,增强自己对平台内容的管控程度,从禁用 eval
和 new Function()
上就能看出一二。
当然微信也知道架构所带来的性能问题,所以发明了 WXS
,让一部分 js
代码能在渲染层跑,部分解决通信消耗和延迟的问题,只能满足很小一部分场景,依旧很鸡肋。
理论上是可以在wxs中访问到window对象的,因为wxs代码运行在
webView
中,但是微信对wxs功能做了阉割限制,只提供很少一部分功能,尤其不能让用户操作DOM。
综上所述,优化setData
是一个小程序应用无法忽略的关键一步,它占了小程序性能体验的大头,理应贯穿整个小程序开发周期。
# Skyline 渲染引擎
小程序一直以来采用的都是 AppService 和 WebView 的双线程模型,基于 WebView 和原生控件混合渲染的方式,小程序优化扩展了 Web 的基础能力,保证了在移动端上有良好的性能和用户体验。尽管各大厂商在不断优化 Web 性能,但由于其繁重的历史包袱和复杂的渲染流程,使得 Web 在移动端的表现与原生应用仍有一定差距。
为了进一步优化小程序性能,提供更为接近原生的用户体验,我们在 WebView 渲染之外新增了一个渲染引擎 Skyline,其使用更精简高效的渲染管线,并带来诸多增强特性,让 Skyline 拥有更接近原生渲染的性能体验。
当小程序基于 WebView 环境下时,WebView 的 JS 逻辑、DOM 树创建、CSS 解析、样式计算、Layout、Paint (Composite) 都发生在同一线程,在 WebView 上执行过多的 JS 逻辑可能阻塞渲染,导致界面卡顿。以此为前提,小程序同时考虑了性能与安全,采用了目前称为「双线程模型」的架构。
Skyline 创建了一条渲染线程来负责 Layout, Composite 和 Paint 等渲染任务,并在 AppService 中划出一个独立的上下文,来运行之前 WebView 承担的 JS 逻辑、DOM 树创建等逻辑。这种新的架构相比原有的 WebView 架构,有以下特点:
- 界面更不容易被逻辑阻塞,进一步减少卡顿
- 无需为每个页面新建一个 JS 引擎实例(WebView),减少了内存、时间开销
- 框架可以在页面之间共享更多的资源,进一步减少运行时内存、时间开销
- 框架的代码之间无需再通过 JSBridge 进行数据交换,减少了大量通信时间开销
而与此同时,这个新的架构能很好地保持和原有架构的兼容性,基于 WebView 环境的小程序代码基本上无需任何改动即可直接在新的架构下运行。WXS 由于被移到 AppService 中,虽然逻辑本身无需改动,但询问页面信息等接口会变为异步,效率也可能有所下降;为此,我们同时推出了新的 Worklet 机制,它比原有的 WXS 更靠近渲染流程,用以高性能地构建各种复杂的动画效果。
# Skyline 渲染引擎特性
- 性能为首要目标:Skyline精简了CSS特性,保留现代CSS集合,同时添加了大量特性以构建类原生体验的小程序。
- 与WebView混合使用:小程序可以按页面粒度选择使用WebView或Skyline进行渲染,Skyline页面可以和WebView页面混跳。
- 更好的性能:Skyline渲染流程精简,精确控制节点渲染,避免不可见区域的布局和绘制,提高渲染性能。
- 同步光栅化策略:Skyline采用同步光栅化策略,相比WebView的异步分块光栅化策略,减少快速滚动时的白屏问题和DOM更新不同步问题。
- 单线程版本组件框架:Skyline默认启用glass-easel组件框架,降低建树流程耗时,setData调用无通信和序列化开销。
- 组件下沉:部分内置组件如scroll-view、swiper等借助底层实现,view、text、image等组件从JS下沉到原生实现,降低创建组件开销。
- 长列表按需渲染:Skyline优化scroll-view组件,只渲染在屏节点,并增加lazy mount机制优化首次渲染长列表性能。
- WXSS预编译:Skyline在后台构建时将WXSS预编译为二进制文件,避免运行时解析开销,预编译速度比运行时解析快5倍以上。
- 样式计算更快:Skyline通过精简WXSS特性简化样式计算流程,使用局部样式更新,避免全量计算和多次DOM树遍历。
- 降低内存占用:Skyline只有AppService线程,多个页面共享渲染引擎实例,降低页面内存占用,实现细粒度资源共享。
- 根除旧有架构问题:Skyline解决了WebView架构下的一些基础体验问题,如原生组件同层渲染不稳定、页面恢复机制、页面栈层数限制等。
- 全新的交互动画体系:Skyline提供Worklet动画、手势系统、自定义路由、共享元素动画等,实现像素级可控的交互动画。
- 内置组件扩展:Skyline扩展了scroll-view等内置组件,添加了下拉刷新、下拉二楼、sticky吸顶、scroll-view控制能力等特性。
- 更多的高级能力:Skyline提供了grid-view瀑布流组件、snapshot截图组件、scroll-view组件支持列表反转等高级特性。
# 小程序和 PWA
# 小程序架构
小程序的框架主要由三部分组成,分别是视图层,逻辑层和 JS绑定。其中:
- 视图层,用来展示用户的 UI,通过 Web 内核的 WebPage 来进行展示。
- 逻辑层,运行开发者代码,在一个独立的 JS 线程环境中,这个 JS 环境在 Android 是独立的 V8 提供的,iOS 上是 JSCore 。
- JSAPI,都是通过 JS 绑定,将平台和微信相关的能力暴露给逻辑层,从而给开发者提供相应的 JSAPI 接口。
- setData,传输视图层和逻辑层的数据。
# PWA 架构
PWA 的运行环境,是一个完整的 Web 内核。
- index.html:类似小程序的视图层,运行在 Web 内核的 Rende r线程,可以执行 JS。
- sw.js:类似小程序的逻辑层,运行在 Web 内核的 ServiceWorker 线程,管理 PWA 的生命周期。
- JSAPI:Web 内核通过 WebIDL 绑定的方式,将底层能力暴露出来。
- postMessage:用于给 ServiceWorker 线程和 Render 线程提供通信能力,性能非常好,支持 Transferable 对象传输。
# 小程序和 PWA 的区别
以看到小程序和PWA的主体上都是双线程架构的模型,但是有区别的是:
- 视图层:PWA 可以执行 JSAPI,小程序不行。
- 逻辑层:PWA的 JSRuntime 是 Web 内核提供的,不再需要独立的 V8。
- JS 绑定: PWA 的接口都是标准的 H5 能力,通过 WebIDL 绑定,小程序是微信相关接口能力,独立绑定。
- 另外就是,PWA 的应用开发者拥有完全的代码控制能力,但是小程序为了保护微信相关数据安全,都会让开发者代码运行在一个沙箱环境上。
PWA 的优点非常多,其中有几点非常值得小程序学习:
- Service Worker 线程,非常轻量,不再需要额外的V8环境。
- PostMessage:支持结构化 Clone 和 Transable 对象传输,性能非常高。
- PWA 还拥有非常丰富的H5 API,比如 Canvas、WebSocket 等。
- PWA 拥有 Chrome Devtools 的 Inspector 能力,非常方便进行调试。
# 小程序与 RN
现有的混合开发类型,基于 UI 渲染的分类来看,主要有两类:
- 基于 WebView UI 的基础方案。市面上主流,例如微信 JS-SDK,通过 JSBridge 完成 H5 和 Native 的双向通讯,从而赋予 H5 一定的原生能力 - 小程序
- 基于 Native UI 的方案,例如 React-Native、Weex、Flutter 等。在赋予 H5 原生 API 能力的基础上,进一步通过 JSBridge 将 JS 解析成虚拟 DOM 传递到 Native,并使用原生渲染 - RN
# React Native
# 框架
React Native 框架主要有三层:
- JS 层:该层提供了各种供开发者使用的组件以及一些工具库(事件分发等)。
- C++层:主要处理 java/OC 与 JS 的通信(JSBridge)以及执行 JavaScript(JS 脚本引擎)。
- Native 层(Object C/Java 层):主要包括 UI 渲染器、网络通信等工具库。根据不同操作系统有不同的实现。
# 渲染
React Native 基于 react 框架(Virtual Dom)来进行 UI 渲染,具体的流程大致如下:
- 首先 JS 层通过 JSX 编写的 Virtual Dom 来构建 Component
- Native 层将其转成真实 DOM 插入到原生 App 的页面中。
- 当有变更,通过 diff 算法生成差异对象
- 最终由 Native 层将差异对象应用到原生 App 的页面元素上。
# 通信
React Native 基于 JSCore 实现 js 与 java/oc 交互,具体流程大致如下:
- 把 JSX 代码解析成 javaScript 代码
- 读取 JS 文件,并利用利用 JS 脚本引擎执行
- 返回一个数组,数组中会描述 OC/Java 对象,描述对象属性和所需要执行的方法,这样就能让这个对象设置属性,并且调用方法。
# 优缺点
优势
- 原生渲染,性能更好,用户体验较好;
- React 生态较好,对前端开发友好;
- hybrid 技术跨平台开发,成本及难度低于原生;
- 可热更新,能够方便迭代。
劣势
- 支持的样式是 CSS 的子集,会满足不了 Web 开发者日渐增长的需求;
- 现有能力下还存在的一些不稳定问题,比如性能、Bug 等;
- 把渲染工作全都交由客户端原生渲染,会有更接近原生的体验,但实际上一些简单的界面元素使用 Web 技术渲染完全能胜任;
- React Native 之前爆出了一个开源协议问题(Facebook BSD+Patents ,大致内容是使用基于 Facebook BSD+Patents 协议的开源项目的开发者,未来要是因为专利问题与 Facebook 产生纠纷,那么 Facebook 将有权停止你使用该开源项目),这对于之后也是存在隐患的。
# 小程序与 RN 相同点
- 都具有 hybrid 技术的优点:接近原生的体验,跨平台开发
- 使用 Web 相关技术框架来编写业务代码,React Native 为 React 框架,小程序为小程序开发框架。
- 各自实现了跨语言通讯方案完成 Native(Java/Objective-c/…)端与 JavaScript(小程序中为渲染层和逻辑层)的通讯
# 小程序与 RN 不同点
小程序使用浏览器内核 WebView 来渲染界面(小部分原生组件由客户端参与渲染),界面主要由成熟的 Web 技术渲染,辅之大量的接口提供丰富的客户端原生能力,而 React Native 是客户端原生渲染。理论上 React Native 相对于 WebView 的性能更好,但小程序的类 web 开发对开发来说入门相对简单,像是一种开发效率与性能的双刃剑。
微信小程序基础架构浅析 (opens new window)
Web内核微信小程序框架实践 (opens new window)
← Code Push 热更新 数据通信与渲染 →