【深入解析】跨端框架的核心技术到底是什么?
本文是我在学习多个平台 UI 框架后的一些感触,受精力和技术水平所限,文中定有不足之处,请各位大佬多多指教
如果你觉得我的文章对你有帮助,在收藏的过程中,一定要记得点赞和点在看哦,谢谢你,这对我真的很重要🌟!
一、前端三板斧
正式讨论「跨端开发」这个概念前,我们可以先思考一个问题:对大部分前端工作来说,前端主要干些啥?
我个人认为,无论环境怎么变,前端基本上就是做三件事情:
没了。
也许有人觉得我说的太片面,其实我们可以理一理。往近了说,现在知识付费搞的如火如荼,动不动就搞个「XXX 源码解析」,分析一下这些课程的主题和目录,你就会发现基本都是围绕着这三个方向展开讲的;往远了说,我们可以分析一下 Web 前端的发展历程:
最近几年,网络协议趋于稳定,几年内也不会有啥大的变动;国内 React 和 Vue 的地位基本稳固,一堆前端盯着 GitHub 进度条等版本更新;render 层出了不少幺蛾子,好不容易摆脱了 IE6,又来了各种小程序,同一套业务逻辑写好几遍不经济也不现实,这时候各种跨端方案就整出来了
经过一番分析,这个三板斧理论看上去已经有些道理了,我们顺着这个方向再向底层思考:这三大功能是怎么实现的?
经过上面的分析我们可以看出,前端的主要技术核心就两个:虚拟机和渲染引擎,这也意味着,如果我们想要搞跨端开发,就必须得统一虚拟机和渲染引擎。
二、虚拟机和渲染引擎
1.网页:JS Engine + WebKit
因为谷歌的 Blink 引擎 fork 自苹果的 WebKit,后文为了描述方便,统一用 WebKit 代替浏览器渲染引擎
网页是成本最低上手最快的跨端方案了。得益于互联网开放式理念,网页天生就是跨端的,无论什么渲染框架,WebView 都是必不可少的核心组件。
开发人员的接入成本也极低,主要技术就是 Web 开发那一套,前端主要头疼的是各个渲染引擎的适配问题和性能问题。
现在主流的 JS Engine 是苹果的 JavaScriptCore 和谷歌的 V8,主流的渲染引擎是苹果的 Webkit 和谷歌的 Blink。虽然 W3C 的规范就摆在那里,各个浏览器厂商再根据规范实现浏览器,这也是网页跨端的基础。问题在于浏览器内核实现总有细微差距,部分实现不合规范,部分实现本身就有 Bug,这也是前端摆脱不了适配需求的本质原因。
另一个是性能问题。其实 WebKit 本身的渲染速度还是很快的,但是受限于一些浏览器特性,比如说极其复杂极其动态的 CSS 属性,DOM 树和 CSSOM 的合并,主线程必须挂起等待 JS 的执行,这些都会大大降低性能,前端搞性能优化,一般得依据这些浏览器特性进行减枝处理,但是再怎么优化,在页面性能和交互体验上,和 Native 还是有很大的距离。
2.网页 PLUS:JS Engine + WebKit + Native 能力
直接拿个 URL 扔到 WebView 里是最简单的,其实这样也能解决大部分问题,毕竟前端 90% 的工作都是画 UI 写业务逻辑,但是还有 10% 的功能做不到,比如说要和 Native 同步状态,调用一些系统功能。
要实现客户端和网页双向通讯的话,一般都是借助 JSBridge 进行通信,《JSBridge 的原理》这篇文章总结的不错,感兴趣的同学可以看一下。
JSBridge 只是解决了 Native 和 Web 的互相调用问题,如果我想借助 Native 加强 Web 怎么办?这时候就有了一些探索:
经过上面几步,网页的速度基本可以达到秒开的级别,这里面最典型的就是几大新闻客户端,大家可以上手体验一下。
3.小程序:JS Engine + WebKit
小程序,国内的特色架构,本质上是微信成为流量黑洞后,想成为流量分发市场管理和分发自己的流量,所以这是个商业味道很重的框架。
小程序在技术上没什么特别的创新点,本质上就是阉割版的网页,所以微信小程序出来后各个流量寡头都推出了自己的小程序,正如有人吐槽的,小程序的实现方式有 9 种,底层实现多样化,各个厂实现还没有统一的标准,最后就是给开发者喂屎,我也没啥好介绍的,就这样吧。
4.React Native:JS Engine + Native RenderPipeLine
React 2013 年发布,两年后 React Native 就发布了,前几种跨段方案基本都是基于浏览器技术的,RN 这个跨段方案的创新性在于它保留了 JS Engine,在渲染引擎这条路上,他没有自己造轮子,而是复用了现有的 Native 渲染管线。
这样做的好处在于,保留 JS Engine,可以最大程度的复用 Web 生态,毕竟 GitHub 上轮子最多的语言就是 JavaScript 了;复用 Native RenderPipeLine,好处在于脱离 WebKit 的历史包袱,相对来说渲染管线更短,性能自然而然就上去了。
那么问题来了,RN 是如何做到跨端的?这个其实全部仰仗于 React 的 vdom。
vdom
前端社区上有些文章讨论 vdom,总会从性能和开发便捷性上切入讲解,从纯 Web 前端的角度看,这些的确是 vdom 的特点,但是这不是 vdom 真正火起来的原因。vdom 更大的价值在于,人们从 vdom 身上看到跨端开发的希望,所以在 React 出现后 React Native 紧跟着出现是一件非常自然的事情。为什么这么说?这个就要先溯源一下 UI 开发的范式。
UI 开发主要有两大范式:Immediate Mode GUI(立即模式) 和 Retained Mode GUI(保留模式)。
简单来说,IMGUI 每帧都是全量刷新,主要用在实时性很高的领域(游戏 CAD 等);RMGUI 是最广泛的 UI 范式,每个组件都被封装到一个对象里,便于状态管理和复杂的嵌套布局。无论是网页、iOS、Android 还是 Qt 等桌面开发领域,都是基于 RMGUI 的。这两者的具体细节差异,可以看这篇知乎回答和这个 Youtube 视频。
我们再回到 React Native 中,既然 iOS Android 的原生渲染管线都是 RMGUI 范式,那么总是有相似点的,比如说 UI 都是树状嵌套布局,都有事件回调等等。这时候 vdom 的作用就出来了:
vdom 作为一个纯对象,可以清晰的提炼出出布局的嵌套结构,而且这个抽象描述是平台无关的,那么我们就可以利用 JS 生成 vdom,然后将 vdom 映射到 Native 的布局结构上,最终让 Native 渲染视图,以达到跨平台开发的目的。
到这里如果你有些编译原理的知识,你就会发现 vdom 和 IR 有些类似,同样都是抽象于平台的中间态,vdom 上接 React 下接 Native RenderPipeLine,IR 上接编译器前端下接编译器后端,我们只要关心前半段的逻辑处理,脏活累活都让后半部分做。
Hermes
2019 年 Facebook 为了优化 React Native 的性能,直接推出了新的 JS Engine——Hermes,FB 官方博文介绍了很多的优点,我个人认为最大的亮点是加入 AOT,传统的 JS 加工加载流程是这样的:
Babel 语法转换
→ Minify 代码压缩
→ install 下载代码
→ Parse 转为 AST
→ Compile 编译
→ Execute 执行
Hermes 加入 AOT 后,Babel
、Minify
、Parse
和 Compile
这些流程全部都在开发者电脑上完成,直接下发字节码让 Hermes 运行就行。
这样做的好处在于,可以大大缩短 JS 的编译时间,不信的话大家可以用 Chrome 分析几个大型网站,JS 的解析加载时间基本占时都是 50% 以上,部分重型网站可能占时 90%,这对桌面应用来说还好,对于电量和 CPU 都要弱上一线的移动平台来说,这些都是妥妥的性能杀手,Hermes 的加入可以大大改善这一情况。
目前 React Native 0.64 也支持 Hermes 了,如果有做 RN 业务的同学可以玩一玩,看看在 iOS 上的性能提升有多大。
5.Flutter: Dart VM + Flutter RnderPipeLine
Flutter 是最近比较火的一个跨端方案,也有不少人认为这是最终的跨端方案,毕竟桌面软件时代,最终胜出跨端方案就是 Qt,他们的共同特点就是自带了一套渲染引擎,可以抹平终端差异。
Flutter 的创造还是很有意思的,这里有个 Eric 的访谈,视频中说 Eric 差不多有十几年的 Web 渲染领域工作经验,有一次在 Chrome 内部他们做了个实验,把一些乱七八糟的 Web 规范去掉后,一些基准测试甚至能快 20 倍,因此 Google 内部开始立项,Flutter 的出现了。至于 Flutter 选择 Dart 的理由,坊间一直传说 Flutter 开发组隔壁就是 Dart 开发组,离得近就好 PY 交易,反正 Dart 也没人用,没啥历史包袱,可以很好的相应 Flutter 的需求。
Flutter 的架构也是比较清晰的:
从纯粹程度上看,Flutter 是做的最彻底的,虚拟机和渲染引擎都没有用业内的成熟方案,而是自造了一套,好处就是没啥适配压力,坏处就是太新了,业务开发时往往会遇到无轮子可用的尴尬状态,如果谷歌大力推广,国内大厂持续跟进,前景还是很光明的。
6.其它方向的探索:JS Engine + Flutter RnderPipeLine?
社区里有一种声音,认为 Flutter 最大的败笔就是不能用 JavaScript 开发。这时候就会有人想,如果我们把 Web 技术和 Flutter 技术结合起来,用 JS Engine 对接世界上最大最活跃的 JS 社区,用 Flutter 渲染引擎对接高性能渲染体验,国安民乐,岂不美哉?
目前来说一些大厂还是做了一些探索,我看了一些分析和项目架构,感觉就是做了个低配版的 React Native,React Native 的现有架构有一个性能瓶颈就是跨语言调用成本比较高,而这些大厂的调用链路多达 4 步:JS
-> C++
-> Dart
-> C++
,更加丧心病狂,目前看无论是上手和推广都是没有直接用 RN or Flutter 方便。
三、各跨端方案的不足之处
跨端方案不可能只有好处的,各个方案的坏处也是很明显的,我下面简单列一下:
总的来说,在牺牲一定用户体验的前提下,跨端方案可以提高开发者的开发效率和公司的运行效率,我个人认为,只要某个方案的 ROI 比较高,其实是还是可以投入到生产的。
四、总结
本文到此就结束了,我把各个跨端技术提炼为为虚拟机和渲染引擎技术,然后以这两个核心技术的角度去拆解各个跨端方案。一旦概念理清,在面对性能调优等技术场景时,就能抓住主要矛盾,更快更好的发现问题,解决问题。
如果你觉得我的文章对你有帮助,在收藏的过程中,一定要记得点赞和点在看哦,谢谢你,这对我真的很重要🌟!
最后推荐一波我的微信公众号:卤蛋实验室和我的个人博客:supercodepower.com, 目前专注前端技术,对图形学也有一些微小研究,欢迎大家来撩~
五、推荐阅读
【答疑解惑】为什么你的 Charles 会抓包失败?
webpack 中那些最易混淆的 5 个知识点
【全网最全】React Native 性能优化指南
【独家】React Native 版本升级指南
标签:
相关文章
-
无相关信息