大前端的下一站何去何从?
作者|赵祥辉(华泰证券互联网前端团队)
编辑|覃云
近年来,移动互联网应用有着爆发式的增长,同质化 APP 层出不穷,人们对于产品体验的要求越来越高,渲染迟缓、交互卡顿的单体 Web APP 已经无法满足现有用户苛刻的使用标准;与此同时,井喷式的业务需求迫使 iOS、Android 两个移动平台不断提升迭代开发速度,缩短版本发布周期;如何既能利用 Web 门槛低、轻量级、跨平台开发的优势,又能尽可能最大化屏蔽其现存缺点成了大前端融合领域攻克的重点。
本文借用主流移动跨平台开发方案,向大家介绍移动平台开发的演变之路。
Hybrid-App 的天下
移动应用开发领域发展至今已基本被 Android、iOS 两大平台统治,每个平台仍在不断发展完善、壮大自己的生态系统;对开发者而言每个平台更像是一个巨大的 SDK,为我们抹平了设备硬件、系统内核所带来的差异,统一了平台设计、开发方式。
Figure 1 移动开发平台概览
为了追求极致的开发效率、降低研发成本,早期的开发者不断尝试利用新技术突破平台所带来的约束,PhoneGap 技术 (旨在让早期的 Web-App Written once, run everywhere ) 的出现让开发者们看到了 Hybrid-App 的雏形。
PhoneGap 技术基于 WebView 引擎中的 JS Core 解释器,其核心是 Cordova JavaScript 类库,这层 JavaScript Plugin 抹平了不同平台间的差异,为 Web 与 Native 交互提供了统一的抽象接口及完善的调用机制,其本质是将不同平台打造为一个接口统一的 Web 壳资源平台:UI 渲染依赖平台 Web Render 处理,统一使用 HTML+CSS 绘制;交互逻辑使用 JS Core 这种方式在早期大大降低了开发成本、同时也缓解了早期特定移动平台开发人员稀缺的问题,早期定义的 Hybrid-App 更像是基于移动平台开发的 Web App。
Figure 2 基于 PhoneGap 开发的移动 APP
伴随业务规模的发展,人们发现这种方式虽然高效,但是用户体验却是一团糟;虽然实现了跨平台开发,但又被有限的插件资源所限制;移动开发领域初期,系统平台众多,一系兼容处理让整个框架变得臃肿,这令原本就性能堪忧的框架更是捉襟见肘。随着前端技术的进步,开发者们也在不断打磨 Cordova 框架:提升整体加载性能、增强插件扩展灵活性,从大刀阔斧到精雕细琢,Cordova 生态系统逐渐完善, 众多公司也纷纷开始围绕 Cordova 及一些主流的前端框架打造自己的专属移动开发平台,Hybrid-App 也从青涩步入成熟。
Figure 3 基于 Cordova Plugins 的主流 Hybrid APP 框架
这里不得不提到影响了近几年前端设计思想的 UI 框架 React.js,其设计初衷是优化 web 在移动端的渲染性能、改变传统的 UI 开发方式:
组件的概念 - React 基于 UI 组件构建视图,每个组件负责维护自己的(State)展示状态,利用简单的 UI 组件创建复杂的 UI;利用组件组合后形成的单向数据流,根据 State 的变化来刷新 UI 展示;同时推出了更便于组件化开发的 JSX(JS 语法糖) 语言。
Visual DOM:React 一个颠覆性的创新就是引入了二进制 Visual DOM 树,其本质可以理解为在 JS 和 DOM 之间做了一个缓冲层用于保存 Virtual DOM 树,UI 状态变化时只比较新旧 Visual DOM,通过 Diff 算法找出节点差异,然后进行真实 DOM 操作。因为操作 HTML DOM 是非常耗费系统资源的,通过这种方式可以保证以最小代价刷新 UI。
轻量级的 UI 框架:可以和其他前端框架结合使用,React.js 只是单纯的 UI 框架,也就是常说的 MVC 框架中的 View 层,它借用了响应编程模式的特点来简化 Web 视图的创建过程;Model 层 和 Controller 层的缺失催生出了 Flux 和 Redux(Redux 可以视为 Flux 框架的精简版) 框架。
这里仅以使用比较广泛、知名度更高的 Redux 框架来介绍,Redux 框架的核心理念是严格的单向数据流,只能通过 dispatch(Action) 的方式修改 Store 数据 (Store 的概念源自 MVCS 框架,Store 不仅仅是 Model 的概念,理解为前端中的 DB 形式更为贴切),其流程可以简单描述为:View -> Action -> Reducer(logic process) -> Store(change/write/delete state)。
Redux 的设计理念是不是看上去和 React.js 不谋而合?再加上 Redux 社区还基于异步流扩展了很多 Extensions 插件(redux-trunk、redux-promise、redux-saga、redux-observable 等),所以很多厂商纷纷选用 React+Redux 作为自己的 Web 支撑框架。
至此,也就形成了业内主流的 Hybrid-App 框架 Cordova+React+Redux,但是由于 Web 有着先天的局限性,前端框架只是从架构设计、算法层面对性能进行优化,仍然无法解决根本问题:
- 首次渲染效率及白屏问题;
- 单线程的状态分发机制,无法满足复杂用户交互场景(滑动,拖动手势)。
- 首次创建 Virtual DOM 树的耗时相当于延迟了首屏渲染时间;
- 每次 State 变化都会生产全量 Virtual DOM 树,和上一次结果做 diff,这其实是一次算法执行时间与 Real DOM 操作时间的博弈;
-
需要编写大量的闭包函数(Redux 也有同样的缺陷)。
随着业务爆发式的增长、交互复杂度提升、数据请求不断增多,如果要 Redux 承载整个 App 或大部分关联 Web 的数据处理已经非常困难: - Store 中存放的冗余数据越来越多,维护了多个 Web 页面的组件状态;
- 直接在 reducer 中操作 View 与 Model,几层 reducer 之后很难明确 Model 已经被加工成何种形式;
- 一直会有下一个基于 Redux 的改良封装 Extensions;
- 异步、同步相互依赖场景,复杂 UI 交互,恐怕大部分精力都在考虑 reducers 怎么拆分了。
不可否定的是,React 和 Redux 是伟大的框架,他们设计思想、核心理念对后续移动领域的发展有着深刻的影响;移动互联网技术的发展反而放大了它们的先天缺陷,这也加快了 Hybrid-App 的进化速度。不甘平庸的产物
在 W3C 制定 HTML5 标准之初,FB 的创始人扎克伯格就曾口出狂言要用 HTML5 技术统一移动端,无奈宣告最终押注失败,随后 React、Redux Web 框架的相继推出表明了他们并未真正放弃,这也为 2015 年 FaceBook 发布 React Native 框架买下了伏笔。
一心想统一移动端开发的 FaceBook 在 2015 年宣布了只用 JS 语言开发 Native 应用的框架 React Native(后文称:RN),并提出了新的口号:Learn once write anywhere,新框架强调的是 UI 绘制、交互逻辑思想、开发方式的统一,与 Cordova 不同的是 RN 将 JS 中定义的组件标签都转义成了原生对应的 UI 组件,直接抛弃了 WebKit 中渲染、绘制功能,全部使用 Native 资源,其核心思想是基于 JavaScript 虚拟机将 JSX 编写的组件映射为 Native UI 组件。由于 RN 技术天生就引用了自家的 React.js 技术框架又有整合了 Native 平台 UI 组件,在发布之初让广大前端开发者看到了新的希望。
不同平台的 JS 虚拟机为 RN 提供运行时 JS Context 环境,其中注入了 RN 转义 Native UI 组件的接口,相较于传统的 Cordova 形式的 Hybrid-APP,不深究细节的话,可以认为 RN 使用了原生 UI 组件完美替换了 Web Core 中的 H5 + CSS 的绘制框架。
Figure 4 React Native 跨平台开发框架
由于使用了原生 UI 组件,其渲染速度和 UI 流畅度有了质的飞越,前期很多 Web 页面无法支持的效果也可以使用 RN 来实现;只使用 JS/JSX 开发,兼容 Web React.js、Redux.js 等主流框架,RN 自身也实现了大部分 UI 组件的集成工作,再借助活跃的社区,开发效率相比于原有的 Native+Web 形式的 Hybrid-App 有了显著提升。
虽然 RN 在发布早期备受关注,甚至一些互联网企业已经发布了 RN 的商业化平台,但是业内仍然出现了“RN - 由入门到放弃”的声音,究其原因,主要可以归结为以下几类: - 无法完全抹平跨平台 JS Engine 的差异性,JavaScript Core 的不一致性,RN 的 Android 版本仍然不支持 ES6 的 JSC;
- 发布快四年之久,仍为 0.x 版本,还不能满足 1.0 版本的稳定性(近期 Facebook 又在对 RN 进行大规模重构);
- RN 社区开源库质量参差不齐,很容易跳进坑里;
- 很多基础框架的库还是不支持 RN,需要自己封装;
- 学习成本高,为了输出一个稳定的版本既要熟悉 iOS 平台特性又要兼顾 Android 平台兼容性;
- 启动时间长,向单一 JSC 中注入一段庞大的 js 插件仍然需要很长时间,即便只是注入基础插件库;
- RN 框架每一次版本升级所带来的接口向下兼容问题;
- JS 是单线程的解释性语言,手势、动画仍然是无法解决的痛点;
- Android 9.0 已经开始着手对插件进行主动封堵,这也会给各种形式 Hybrid 带来一定影响。
Facebook 起初正是考虑到不同浏览器 WebKit 内核的差异性以及 web view 所造成的内存、性能损耗,所以才决定仅仅基于 JS VM,只使用单一的 JavaScript 语言来完成跨平台开发的统一,却忽视了不同平台系统、版本所带来的差异;还有就是 JS 解释性语言先天的单线程执行所带来的硬伤,始终无法屏蔽 JS VM 的效率损耗;有没有哪种框架可以避免这种硬伤,又能满足跨平台开发的需求呢?搅局者 Flutter 出现了。搅局者
Google 这种以创新为本的公司当然不满足于 RN 这种带有瑕疵的框架,Google 开启了 Flutter 框架的开发,至今已发布 1.0 Release 版本。Flutter 从设计初期就选用可编译成机器码的 Dart 语言开发并且决定将 UI 组件和渲染器从平台移动到应用层中,直接避免了由 JavaScript Bridge 引起的性能问题并最大可能降低了系统平台的差异。
Figure 5 Flutter 跨平台开发框架
Flutter 实际上是在已有移动平台中搭建了一套独立的开发系统,它也是至今为止唯一提供响应式视图而不需要桥接器的移动 SDK,Flutter 唯一要求是系统提供的 Canvas 、访问事件(触摸、定时器等)和服务(位置、相机等)。其整体架构设计可以总结为一下几点:- 一切皆为 Widget,这与 React 中一切皆为组件类似,不过 Widget 承载的定义更广泛一些;
- 使用 Google 自家的 Dart 语言开发 Flutter Widget,Dart 语言的主要特性就是可编译为机器码,无需依赖桥接器;
3.Flutter 框架在设计上引入了分层结构,每一层都简历在前一层之上,并且开源全部框架代码(个人认为在 Preview 版本全部开源并不利于生态发展);
4.Flutter 直接基于 GPU 引擎绘制,抛弃系统 UI 组件(原文引用:借助可移植的 GPU 加速的渲染引擎以及高性能本地 ARM 代码运行时以达到跨设备跨平台的高质量用户体验);
5.Debug Mode 支持 hot reload,减少开发阶段编译、调试时间。
Flutter 框架因为直接基于 Canvas 开发,这也显著降低了在旧版本操作系统上进行兼容性测试的需求;Dart 也拥有和 NPM 类似的软件包仓库,这些软件包也可以扩展当前应用的能力。想为开发者打造一套独立的开发框架,当然你也会猜测到,Flutter 框架不会太完美:
- Dart 语言的嵌套地狱
- 由于 Dart 编译器使用了 tree shaking 等技术,也因而在 Flutter 中禁止了 Dart 支持的反射特性
- Flutter 无法使用 iOS、Android 自带的设计样式
- 将 Flutter 开发框架植入现有 iOS、Android 开发工程要做很多适配工作
- 完全开源的 preview 框架让人担忧其框架生态的健康发展
涨乐现有 Web 容器方案
涨乐 APP 受限于现有架构和业务需求,对于 RN、Flutter 等框架保持谨慎的态度。我们当前采用 Hybrid 形式进行开发,交互复杂、安全要求较高、内存资源占用高的业务(如:行情、交易、活体检测、双向视频等)均由 Native 开发;场景比较单一、样式频繁变更、交互简单的需求页面则使用 Web 开发。
涨乐 APP 中现有的 Web 框架并未采用 jsBridge 注入的方式,而是仿造 Spring 的设计思路,将现有 Native APP 打造为了一个 Local Server 平台,将 Native 功能打造为一个个独立的 Service 组件,仿造 Rest 接口统一 Native -> Service、Web -> Service 调用协议;Web 开发人员基于 Ajax 调用不同的 Service 组件,LocalServer 负责分发不同的 Service。
涨乐 APP 基于平台优势,拦截了现有 Web 资源加载、请求协议,扩展了 Web 资源的能力及生命周期,避免了传输重复资源耗时;也正是因为有了 Web 拦截机制,涨乐 APP 可以在 Web 容器 初始化的同时进行资源下载操作,这样有效缩短了先初始化容器再下载资源的时间损耗。
相比如 Cordova 方式的优点: - 利用现有移动平台特点,牺牲 Service 调用分发时间换取对内存空间,尽可能减少注入 js 插件体积
- 仿 Spring 框架打造的 Local Server 平台,基于 Service 打造 Native 支撑
- Web 资源加载协议拦截机制,避免冗余资源文件传输,加速
总 结
本文借用几个主流框架简单介绍了大前端跨端技术框架的发展线路,随着移动应用开发技术的不断发展、成熟,最终会形成一套稳定、统一的跨平台开发体系; 开发者对于 web 容器增强、业务插件化、虚拟运行环境等技术框架的不断深耕、雕琢也都在推进大前端技术朝着一个统一的方向前进 -- 多端融合。我们只能通过不断的技术积累、输出,才能追赶上大前端变革的浪潮,让业务更好地依托技术为用户提供更优质的产品体验。