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