前端这门技术,从诞生发展至今不过寥寥十余年。如果说前十年是 PC 前端的时代,那后十年一定是属于移动前端的时代。特别是随着网络制式的发展,移动设备在全球范围内得到了空前的普及,在前端领域,Hybird Web、React Native、Weex、Flutter 等等一系列新的移动前端技术也如同雨后春笋般冒出来,今天来和大家分享一下我对「移动前端开发和 Web 前端开发」的理解。
▐ 阶段一:刀耕火种
十多年前的前端,开发者还在为兼容 IE6 而头疼,框架上 jQuery 是老大,有追求的前端开发可能会使用 Zepto.js 以减少网页体积。这个时候,前端页面主要还是以 PC 为主,这个时候根本没有移动前端的概念,在小小的手机屏幕上流量的页面则是以纯文本为主。
▐ 阶段二:工程化
在 2011 ~ 2014 年之间的历史阶段里,模块化的思路占为主导。当时为了进行 Assets 资源加载器的设计,就制定了模块化的协议规范。当时比较流行的模块化协议就是 AMD(RequireJS)、CMD(Seajs 为代表)、KMD(Kissy 为代表)。在淘宝、天猫,Kissy 应用的很火,所以 KMD 主导天下;在支付宝及外部社区,Seajs 应用的很火,所以 CMD 主导天下,玉伯大大的名气和威望也在前端圈里特别高;而 AMD 在国外比较流行,但渐渐也被后来出现的 CommonJS 规范削弱了气势。
▐ 阶段三:移动化
随着 3G、4G 的发展和 iOS 和 Android 手机在市场的普及量大增,PC 业务主战场也逐渐过渡到移动端。前端的思维模式由 PC 转向了移动端,并向 App 的用户体验看齐。移动端的 HTML5 协议支持不完善,前端的生产配套不全,Android 的屏幕碎片化,所以那个时候的前端开发移动端页面适配的痛苦要远远超过 PC 时代。
▐ 阶段四:框架化
在前端社区,Angular、React、Vue、RN (React Native) 这样的 MV* 框架一个接着一个出现,让前端接受了数据驱动思想的洗礼之外,还借助 RN 完成了移动端的体验升级,包括后来的 Weex、Flutter。
在这个阶段,前端开始有了终端的底层架构组,开始构思前端页面在移动终端上的加载性能和用户体验表现。在阿里巴巴内部,为了解决多端复用的问题,Rax 借助 VDOM 打通 WebView 和 Weex 两端,一套代码跑天下。
▐ 阶段五:垂直化
随着初代 iPhone 的发布,大屏幕手机逐渐变成了主流,移动端的需求开始爆发。在淘宝天猫,每年双十一的移动端成交额逐年攀升,并逐渐占领绝对领先地位。前端的领域也随着这种趋势逐渐细分,按照场景可以简单分为移动(无线)前端开发和中后台前端开发。
移动前端开发面向的是消费者端的 Web 与 轻 App 业务场景,在这个场景下,淘系经过多年的营销活动沉淀,逐渐形成了移动端独特的、轻量级的解决方案,以及模块维度的、面向运营的页面搭建系统。
中后台前端则是面向企业 ERP、CRM 、OA 等偏后的业务场景,如商家后台等系统。在这个场景下,借助飞冰、Fusion Design 等中后台物料,形成可视化的中后台搭建解决方案,为业务的前端、开发或产品角色提供一站式中后台生产解决方案。
曾几何时,移动客户端开发和前端开发是两条没有交集的平行线,但现在我们越来越拥抱两者的合作产物:混合式(Hybird)应用开发,或者用最近比较火的一个概念 -- 大前端技术。
从技术的表现形式思考,本质上客户端开发与前端开发都是终端技术,它的特点是直接面向用户 UI 编程。
▐ 同是 UI 编程,我们面对的痛点是什么?
传统 Web 前端技术的技术局限性
1、资源加载:HTML、JS、CSS、图片等静态资源存放于远端的服务器,需要动态的异步拉取,再拉取数据进行展示,初始化效率上比 Native 慢的多
2、渲染机制:在浏览器的设计中,JS 的执行和页面的布局、Paint 都在同一个主线程,无法并行化,再加上 JS 的性能赶不上 AOT 语言,执行复杂逻辑时导致的卡顿通常会阻塞 UI,再加上冗长的渲染管线,导致浏览器的渲染体验在等量对比 Native 时并不占优势。
3、页面切换:在浏览器中并不存在路由的概念,这导致页面间的切换体验完全依赖于浏览器 Shell 提供的能力,在页面切换的时候会反复加载。当然前端社区中也出现了单页面应用的概念,但是多个页面的资源也显著增加了 JSBundle 的体积,也使页面的开发更加复杂化了。
4、API 能力:浏览器的安全机制是基于同源策略的沙箱机制,这套沙箱机制阻止了前端开发者使用原生系统能力,你只能使用 W3C 标准定义的功能,而且考虑到终端碎片化的问题,这些接口往往不能直接使用。这在 PC 端的场景中是没有什么问题的,但是在移动端则相反,开发者希望有能力调用系统接口实现一些更富交互的场景。
5、交互性能:浏览器的实时交互性能体验差,在复杂交互场景中大规模的重排限制了 UI 帧率,这种限制在中低端移动设备中尤为严重。
6、脚本语言,动态解析执行JS 是一门 JIT 语言,也就是需要动态解析执行,对比预先编译机器码的 AOT 语言的执行性能就差得多了。
传统客户端技术的局限性?
1、动态性:客户端开发通常是有固定的版本发布计划,而且受制于 Apple 的 App Store 审核规则,版本发布的不确定性还会受到政策影响,Android 在国内的渠道众多,每次发版都要反复检查渠道,一旦发现线上问题需要依赖再次发版,容错成本非常高,这也大大增加了对业务的局限性。
2、开发成本:客户端的开发成本高,然而生态还不如 Web 丰富,npm 社区的几万开源包,加上更活跃的开发者社区,导致对企业来讲客户端的研发成本是高于 Web 开发的。
3、跨端一致性:传统客户端开发一套业务,是需要实现 Android + iOS 两套代码的,而且由于 Android 和 iOS 的操作系统能力差异,同样的需求往往会用不同的视觉和交互来实现,这也导致了业务成本居高不下。
▐ 混合式前端开发
为什么会出现混合式前端开发?
随着 iOS + Android 确立了移动操作系统的统治地位,前端开发者也在寻找使用操作系统提供的能力进行业务开发的模式。Web 的开发方式远比 iOS 和 Android 更加方便和高效,Web 上层出不穷的各种库和框架也远比 Android 和 iOS 的各种库和框架方便的多。Web 上我们可以方便的使用各种前端框架,及时预览效果(想想大型 Android/iOS 工程的编译时间)。
从阿里巴巴的角度来看,随着中台化的理念逐渐被接受:业务需要追求快速发展,前台的 UI 和需求会随着商业决策快速迭代,前端和客户端不同的岗位也形成了分工化的研发模式。
前端向上,前置作为业务方的唯一接口,逐渐演变为大前端的业务层。在这一层,它的职责是负责定义规范,通过框架规范业务的开发过程,同时封装统一的解决方案和工程化能力,将重复的工作抽离。
客户端向下扎,解耦业务需求,转为大前端的架构层,给上层的业务开发者提供能力支持。通过将客户端的系统级 API 以及宿主应用的能力暴露给上层前端,提高前端页面对更多富交互场景的承载能力。
在这样的大背景下,各种混合开发技术层出不穷,在这里我们简单的把混合式应用的发展定义为三个阶段:
▐ 阶段一:JSBridge
在这个阶段,主要还是以 WebView 为主,并配合 JSBridge 提供了 Naive 与 JS 之间的通信链路,基于这个通信基础,Native可以暴露出一些标准服务 API 提供给 JS 调用,同样的 JS 也可以以此封装一些基础API给 Native 调用。前端开发者使用传统的 JS + HTML + CSS 进行页面的开发,并且调用 JSBridge API 驱动客户端能力。在这个阶段,Apache Cordova 是业内的佼佼者,大多互联网公司内部也有自己的 JSBridge 框架实现,可以说 JSBridge 第一次给了前端开发者调用 Native 的能力。
但是 JSBridge 方案的主要缺点在于性能方面及高级组件扩展能力缺失,流畅性始终无法与 Native 媲美。
▐ 阶段二:原生 UI
虽然 Web 的动态性和高效的开发效率,是原生开发望尘莫及的,但是浏览器技术的瓶颈也非常明显:
1、W3C 作为开放的技术标准,历史悠久,包袱多,显著拖慢了浏览器的性能。
2、WebView 渲染引擎设计的上的缺陷,渲染流水线非常长,导致浏览器对合成器动画和非合成器动画区别对待,非合成动画性能不好。
3、单线程模型,无法发挥现代硬件架构特别是 ARM 架构多核心的性能。
4、异步光栅化的设计,在进行长列表滚动时,不可避免出现白屏的现象。
**有没有一种两全其美的方式?React Native/Weex 的出现给前端开发者带来了一道曙光。**
React Native/Weex 利用 JS 引擎来调用 Native 端的组件,从而实现相应的功能。React Native 和 Weex 都允许前端开发者使用 JS 进行业务逻辑开发,使用 VDOM 来描述文档结构,并配合 CSS 的子集来定制样式,样式和模板分离。
Weex 体系中, JS 的执行在 JS Thread,Layout 执行在独立的 Layout Thread ,渲染执行在系统的 MainThread ,三个线程相互独立,并行执行。
在 WebView 的体系中 JS 的执行、 Layout 、 Paint 都在 MainThread ,相互影响,在进行复杂任务时会导致界面卡顿。
这种方案的优势在于最大化的复用前端的生态和 Native 的生态体系。
在阿里巴巴,Weex 的大规模应用,甚至支撑起了双十一亿级的流量。
▐ 阶段三:自绘引擎
什么是自绘引擎?
所谓自绘引擎,就是不依赖操作系统提供的布局、原生组件能力,直接调用 GPU 或者底层抽象层进行绘制的渲染引擎。
在上一个阶段,前端开发者已经可以使用 JS 引擎驱动原生 UI 了,为什么还需要自绘引擎?
React Native/Weex 充分将 Native 的 View 体系输出到前端体系中,在进行 Android/iOS Native View 的封装过程中,存在不少难以逾越的障碍。如:难以抹平的双端一致性问题、复杂样式能力难以实现、 Layout 动画需要执行两次(WeexCore Layout 和 Android Native 本身的 Layout )。组件的封装成本随着复杂度增加也越来越高,难以逾越 Native View 限制提供更细致的 W3C 标准能力。
2018 年 Flutter 诞生,通过 Dart 语言构建一套跨平台的开发组件,所有组件基于 Skia 引擎自绘,在性能上和 Native 平台的 View 相媲美,同时解决了上一代架构难以解决的双端一致性等问题。引起大家广泛关注,充分验证了通过绘制构建组件做到 Native View 媲美的 UI 渲染引擎的可行性。
但是 Flutter 本身是缺乏动态更新特性的,社区上也有一些项目在探索 Flutter 的动态化特性,我们团队内部也在实现面向前端的动态化 Flutter 引擎:Kraken,与其它方案不同的是 Kraken 并没有基于 Flutter 自带的 Widgets 框架进行扩展,而是从底层扩展了 W3C 标准的 API,这使得它更像一个浏览器,也让 Flutter 面向 Web 开发者的使用门槛大大降低。
天下大势,分久必合,合久必分。移动前端开发本质上还是终端开发的一种形态,不管容器、框架、语言怎么变,在前端开发者中只有 W3C 的标准是永远不变的。笔者认为,随着 Web 的发展,在解决一系列性能、体验问题之后,浏览器技术会成为更通用的 UI 编程标准。
▐ PWA
早先年,Google 就已经在这一领域内努力,推出了 PWA (Progress Web Application) 的概念。
PWA 通过在移动端浏览器提供标准化框架,在 Web App 中实现和 Native App 接近的用户体验。它的特性其实是一系列 W3C 标准和私有标准集合,简单的说 PWA 支持:
▐ PHA
当然在标准能力不完善,业务又需要定制化能力的当下,混合式应用还会继续发展。
PHA (Progress Hybird Application) 的概念应用而生,PHA 是一种渐进式的混合应用增强策略, 提供端测的辅助能力,提升 WebView 的渲染性能与体验。广义地说,当下比较火的小程序、快应用都是 PHA 的一种实现。
在淘系内部,我们也在实现一套轻量级的 PHA 方案,并且在大促中也取得了不错的效果,我想后面单独出一篇关于 PHA 的文章来阐述。
关于未来,随着技术方案的多样化、以及端边界的扩展,我们认为最重要的就是效率与性能的问题。
基于大数据的机器学习能力,移动端上会拥有更高效的 UI 编排能力,最终能让 UI 渲染实现实时个性化。
基于最近比较热的 WebAssembly 能力,让浏览器突破 JavaScript 的限制,能拥有更大的想象空间。
作者|卓凌
编辑|橙子君
出品|阿里巴巴新零售淘系技术部
来源 : 阿里云开发者社区