编辑 | 马红伟
嘉宾 | 张舒迪
2020 年 12 月,QCon 全球软件大会 2020·上海站上阿里巴巴张舒迪(圣司)分享了《阿里跨端技术演进中的实践与思考》,他从跨端技术背景及演进历程、阿里跨端业务现状及思考、跨端技术方向思路演进以及对跨端技术未来展望这四个方面进行了深入的分析,从实践出发为跨端技术开发者带来更多思考方向。本文根据此次分享整理。
一般来说,跨端技术有 4 类场景,分别是跨设备平台(跨 Web 端和手机端)、跨操作系统(如跨安卓和 iOS)、跨 App 以及跨渲染容器。本篇文章将重点围绕移动领域的跨端技术进行深入探讨。
移动跨端的重点在四类问题的解决上。首先在性能上,如何通过前端和客户端的结合,实现更优的渲染性能以及交互性能;其次在动态性上,客户端怎样能够实现更低成本的发版、甚至不发版直接动态更新代码;第三是研发效率,如何提升客户端动态调试等研发效率;最后就是一致性,如何实现一份代码的多端部署,如何保证代码在多个客户端内展示形态的一致性、杜绝兼容性问题。
为什么说移动跨端开发需要“子集规范”?
从 2008 年苹果发布第一部 iPhone 手机到现在,移动互联网已经发展了十几年,国内移动端领域也经历了诸多技术演进的阶段。在 2012-2013 年,国内最早的移动互联网出现,这个阶段重点解决了通过一份 PC 代码如何在 H5 的浏览器里实现渲染。
2014 年,随着移动互联网的网民数量以及设备数量的爆发式增长,移动开发步入到 Hybrid 技术阶段,重点解决了“互联互通”、“H5 如何与 Native 能力齐平”以及“加载性能差”这三大问题,这一阶段的真正价值是在 Hybrid 加持下,前端技术成为移动互联网时代技术选型之一。随后出现的同层渲染以及 Native 容器化解决的核心问题都是渲染性能差。
再往下小程序开始出现,比起一个从技术角度出发的解决方案,它更像是一个通过技术来实现的产品或者说商业思路。这个阶段在跨端技术发展上是一个很核心的关键点,小程序的出现让业界意识到,我们需要一个能够帮助自己抹平不同容器技术方案的框架,阿里、腾讯、字节跳动纷纷开始布局小程序开发,由此诞生了大量的像 Taro、Uni-App 等一系列跨端解决方案。
再往下一个阶段走,就是现在我们聊跨端技术聊得最火热的一个话题,也是跨端技术绝对的新贵——Flutter。Flutter 给前端带来的最核心思路即提供了自绘渲染技术,可以实现两端完全抹平,它弥补了像 React Native 或者 Weex 通过原生渲染带来的双端不一致以及兼容的成本。
以上是一个通用的跨端技术演进历程,从阿里本身来讲,以飞猪为例,在 Hybrid 的阶段做了 Claims,在 Native 容器化阶段引入了 Weex,在小程序化阶段引入了 Rax,目前在做 Web 技术跟 Flutter 底层引擎渲染能力的对接。
通过调研阿里内部三四十个业务单元当前的业务现状,我们发现了四个主要的跨端技术问题:
技术演进诉求 vs 存量业务支持:端稳定性治理高风险,业务开发人员高门槛,历史包袱逐步锁死技术栈;
大前端协同需要 vs 差异化视角与节奏:框架与容器演进都会对上层业务研发带来影响,节奏不一致导致反复重构,业务开发与架构地位不对等;
多端多场景投放 vs 跨端方案割裂:跨端技术的碎片化演进反而带来了跨端场景兼容适配的高成本问题;
业务迭代效率 vs 技术协同成本:沟通成本、研发成本、调试成本、招聘成本、管理成本
展开来讲,第一个问题,通过调研我们发现其中有 91.7%的业务单元需要把业务投放到多个客户端里去,比如说同时投放到手淘、支付宝以及飞猪团队,这种情况下会导致这些团队的 95.8%的业务需要适配多个渲染容器,这会带来什么问题呢?
以一组数据来说明,阿里内部各业务单元 App 平均接入和维护 3.15 套跨端方案,对应 2.75 套研发框架,这些数据产生的直接原因,就是因为我们没有办法把上一代产出的业务代码进行快速迁移,然而那部分代码也需要在线上进行持续维护,随着时间的发展以及跨端技术的演进,就导致一个 App 里接入的跨端技术方案越来越多、越来越冗余,继而带来“历史包袱锁死技术栈”的严重问题。
在讲第二个问题之前,前端同学需要思考一下什么时候会重构代码?一般来说是架构升级时,比如说需要用 casey 实现 MVC 的架构、React 出现了单向数据流、Vue 碰到了 MVVM,这种时候往往会选择重构代码,在移动互联网时代却不一定是这样,容器技术演进也可能会导致前端的重构代码。举个例子,当 Weex1.0 版本强绑了 Vue 的框架,如果业务单元是 React 的技术栈,也需要切到 Vue 上,换言之 Flutter 也是如此,Flutter 引擎上实际是强绑了 Dart framework,如果要迁移就需要把代码都迁移到 Dart 上去,这就导致了不管是做小程序还是客户端进行同期升级,都需要进行重构。从飞猪的历程来说,发展的 6 年间平均一年重构一次代码。
再来看第三和第四个问题,在没有 Native 端的情况下,阿里各个业务单元的业务平均需要投放到 3.77 个 App、适配 2.54 个渲染容器、编写 2.45 套代码,这反映出来一个现状,随着跨端技术的演进,不同的技术方案散列在不同的容器里,技术选型的不一致带来了大量的跨端问题,最后即使能够用资源冗余的方式去开发这么多套代码,从今天业务研发的视角,每一个问题都需要找到对应的容器协作团队,对接 N 个架构组,沟通协调成本之高可想而知。
那么是不是存在一个简单的解决方案,比如说提供一套统一的跨端解决方案,不再通过升级来解决这个问题?答案当然是否定的。
实际上,跨端技术解决的是 H5 代表的研发效率和动态性以及 App 代表的性能体验之间找平衡点的问题,每一个解决方案它能覆盖的宽度是有限的,如果这两个端点之间的距离太长,就没有办法提供一套方案来解决所有的问题。
那么两个端点之间是否可以拉近?从前端角度来看,性能体验会不会变得更好?在 2014、2015 年阿里刚开始做 H5 的时候,我们还相信随着硬件技术的提升手机性能问题将迎刃而解,但随着时间和技术的发展,新的问题滋生出新的性能优化。实际上,在摩尔定律下拿到的性能红利会被优先用于解决 App 的续航问题,此外,在流量见顶的情况下,每个业务都会倾向于以更多的功能来获取更多的用户,业务的复杂度将会对冲掉硬件升级带来的性能红利。
那从客户端的角度来讲,未来是不是有更好的研发效率和动态性来解决这个问题?答案也是否定的。研发效率问题可能能够解决,但是客户端的动态性问题却解决不了,因为想要解决这个问题就要动到 OS 厂商最核心的利益,苹果不会接受所有应用脱离 iPhone 手机市场进行自由更新。
为了解决这个问题,我们先来重新审视下整个跨端技术的研发。一个页面的开发由三个核心部分组成——研发框架、渲染容器和配套设施。研发框架更多是前端主导,意味着设计模式、MVC、MVVM 单项数据流,渲染容器一般由客户端主导,代表了性能和体验,最后是代表着研发效率的配套设施。在当前的跨端技术演进中,这三者一直都是强绑的关系,一套新的跨端解决方案一定会强绑一套研发框架、一个渲染容器和基础设施。思考一下,通过一些方法能否将三者进行解耦,未来客户端的容器和框架得以实现自由更新与演进,业务也可以同时并行跑在更多的容器中。
从 Web 思路来想这个问题其实很好解,我们把解决方案想象成浏览器的渲染引擎,把业务想象成前端页面,实际上就是当年浏览器大战时的问题解决思路——标准化组织(W3C/WHATWG)。在标准化模式下,所有的前端业务和容器端都只需要对应一套统一标准,这样就把一个 O(M*N)的复杂度问题降低到了 O(M+N)。
以类似的思路去思考,阿里内部所有的渲染容器是不是都可以以统一一套子集规范的方式去做协同,跟此前 Weex、React Native 建立 Web 标准的借鉴思路不同,这是提前制定一套能够让各个容器去做适配的标准。在这个标准之上,我们能够去统一研发框架,支撑上层更多的业务,那这个思路能否解决前文中的几大问题?
第一个是存量业务如何迁移的问题,如果说所有的业务都是基于一套统一的标准来实现,底层容器更新后业务可以平滑迁移,就不存在历史包袱了。第二个问题是当一份代码装在多个 App 里时如何降低复杂度,如果说每个 App 的容器都提供了一套标准化的接口,一份代码自然可以无缝地装到各个容器里去。第三个是协同导致的成本问题,m 个容器跟 n 个业务的同学需要穿插着去沟通交流,试想如果有一个标准化小组作为中间方,m 个业务只需要对标准化小组提交兼容性问题即可,所有的容器也可以根据标准化小组给的排期去做统一的处理,各方都能有一个比较好的结果。
如何实现一个高性能的标准子集?
如上图所示,基于阿里跨端技术的发展,下文将会从 Web 子集标准建设、Web on Flutter 建设思路、统一跨端研发框架与跨端配套基础设施这四个部分入手探讨跨端技术方向演进思路。
Web 子集标准建设
为什么是建 Web 子集标准而非全集?因为全集太复杂了。使用 CanIUse 和 MDN,我们获取了当前前端所有的标准规范,包括 HTML 的元素属性, Web API 规范,接口, CSS 属性/伪类/伪元素,标准事件等等,总共有 2000 多个规范需要匹配,每一个都有非常复杂的业务逻辑,因此无法实现全量。选择一个标准化子集能够解决什么问题呢?
首先是能够控制实现的成本,容器同学优先去实现关键属性,ROI 一定是最高的。其次是能够优化渲染管线,经过 20 年的优化,Web(或浏览器内核)的渲染其实并不慢,但前后标准的无缝兼容带来的复杂度成本却很高。Flutter 创始人 Eric 在一次采访时就曾提到,Flutter 诞生的主要灵感就是在做 Chromium 的性能优化时,他发现把 Chromium 的性能渲染管线上无关紧要的渲染步骤都去掉之后,浏览器的渲染性能提升了 20 倍,这让他意识到一个精简的渲染管线能够铸造更好的渲染性能。
第三是兼容 Web 标准。既然是一个 Web 标准的严格子集,那也就是说业务可以无缝迁移到以 Web View 作为承载,这有两点好处:首先,如果渲染容器、客户端不再进行维护,业务可以随时下线,前端可以无缝降级到 Web View;其次,代码将可以在端外通过浏览器或者说 Web View 来承载,以此实现多投。
第四是复用最佳实践。最佳实践既包含狭义的前端研发框架、前端 NPM 生态,也包含广义的前端人才、前端培训教程等知识储备,我们需要提供给每一个容器进行内部扩展的实例方法,比如优酷 App 有强管控、处理视频的需求,它可以在自有容器内做渲染规范,以此实现自有业务在端内更好的体验。
那如何实现一个高性能的标准子集?标准要如何来定制?
从阿里的实践来看,首先拉通了集团提供渲染容器和前端框架比较大的几个业务单元,如淘宝、钉钉、支付宝等,从中选择架构师同学组成一个标准化的工作小组。接下来观察整个阿里经济体内的前端业务代码仓库,将其使用到的 Web API、CSS 标签制成频度列表,根据频度高低进行选取,每个属性都会带来性能开销及研发支持成本,最后由工作小组内的资深架构师同学进行评估,以此来决定子集标准。
在标准的制定流程上阿里参考了 W3C 的标准规范,包括发起流程、评审流程、草稿标准、实现标准等。目前 CSS 已覆盖 98 条标准,Web API 实现了 260 条标准,HTML 仍在梳理过程中。
Web on Flutter 建设思路
制定完标准之后就要去看底层的渲染容器了。在标准容器实践上,下文将会以 Web 标准如何对接 Flutter 渲染容器这个思路进行相关阐述。
Flutter 的底层实际上是一个 C/C++写的引擎层,基于 Skia 实现了自绘渲染。上层是一个 Dart Framework,里面既包含了响应式能力,也包含了万物皆 Widget 的一个实现。
那怎么来对接?先来看一下 Flutter 在大前端中可能的位置,上图中第 2 列是 Flutter Native 的一个渲染链路,上层走 Dart 的业务代码,然后过 Dart Framework,最后承接在 Flutter 引擎上。左侧的第 1 列实际上是 Flutter 官方提供的 Flutter for Web,虽然也是对接 Web,但思路不同,关键点是如何让 Dart 代码装在我的浏览器里。这里提供了 HTML mode 跟 WebGL mode 这两类解决方案,前者更多使用 HTML 标签、CSS 来进行模拟,存在很大的性能问题,已基本废弃;后者是基于 WebGL 加上 Simbody 来实现的一套训练能力,也是目前正在尝试的方案,缺点是无法做业务存在,关键的能力是当客户端实现以 Dart 为业务代码的页面出现无法渲染的情况时,使用这套方案可以实现无缝、快速做兜底。
第 3 列是前端视角,打通前端跟 Flutter 引擎的对接。最上层的 JSFramework 是我们常用的 React/Vue/Rax,最底层是我们想要复用的 Flutter 引擎,实际上中间可能还需要一层 Framework,而标准子集就在这一层的 Framework 跟上层前端的 Framework 之间来实现,以此实现一套统一的 Web API。最右边的这一列是传统的 Web 渲染链路,这一块就不再赘述了。
整体的技术布局了解之后,下面讲一下具体要如何对接。
Flutter 渲染与前端渲染有很多相似之处,核心就是 Widget Tree、Element Tree、Render Object Tree,其中 Widget Tree 和 Element Tree 可以理解成一个基本等同的数据结构,差异点是 Widget Tree 更多是配置信息,面向的是 Dart 业务的开发同学,是一个比较精简的数据结构,Element Tree 则是框架内部真实实现的实力节点,它里面既包含了 Widget 跟 Render Object 的实力,同时能够在 WidgetTree 到 Element Tree 之间实现 diff 算法。
Render Object Tree 类似前端的 render 区,作用是实现具体的渲染。在 Render Object Tree 这层会进行 Layout(布局)与 Paint(绘制)的动作,形成一个 Layer Tree 扔给 Skia 库,即底层 Flutter 引擎,最终渲染出页面。
试想一下,前端代码对接到这三棵“树”的任意一棵,就能够实现前端跟 Flutter 引擎的对接,从这个思路出发业界已经有很多解决方案,下面简单列举四个:
思路1:遵循 Flutter 思路,对接 Widget Tree
遵循 Flutter 思路,不同的是用 JS 来实现整体 Widget Tree,可以理解为原本由 Dart 写的业务代码在 JS 里进行了 1:1 的实现。这一思路有三点优势,首先是依托 JSC/V8 使 Flutter 具备了动态化能力,其次其改造成本相对可控,第三是可复用部分 JS 生态(工具库)。
同时,这个思路也存在三点需要注意的问题,首先,在 JS 里去写 Widget Tree 不是在写前端,无法对接前端的标准,因此也丧失了 Web 视图的开发特性;其次,JS 部分逻辑较重,性能相对也会较差,第三,实际在 JS Call 对接过程中,会出现 JS 到 C++再到 Dart 再到 C++的一个通信流程,通信开销成本也会相对较高。在具体实践中,腾讯的 MXFlutter 就是沿用了这一思路,更多目的是解决 Native 的动态性问题。
思路 2:遵循 Web 思路,对接 WidgetTree
这一思路同样是对接 Widget Tree 这一层,不同的是在 Dart Framework 里去实现 Dormitory 跟 CSSOM,然后再把 Dormitory 跟 CSSOM 解析成一个 Widget Tree。以一个商品的背景图片为例,它可能由 Container、Decorationimage、Networkimage 三个 Widget 组成,通过 Widget 去匹配 CSS 和 HTML 标签的方式,把 Dormitory 映射成 Widget Tree。
这一方案存在三点优势,它既能够实现跟 Web 生态的对接,改造成本也相对可控,同时因为 Widget Tree 本来就是 Flutter 暴露给上层开发者的数据结构,不会轻易去改动 API,稳定性比较好,未来 Flutter 升级也可以做平滑的迁移。
但是它也有两点问题,首先是会出现两次 diff 消耗,前端的研发框架基本上都会有一层 diff,但在 Widget Tree 到 Element Tree 的转化过程中还会产生一层 diff,这两层 diff 实际上是冗余的,将会导致一定的性能开销。其次,Widgets 的组合完全没有 CSS 灵活,众所周知,前端标准里并不限制 CSS 组合,怎样都不会影响渲染,但在 Flutter 设计里有一些 Widget 是明确不能组合的,这就导致一些 CSS 属性的组合不可能通过拼装 Widgets 的方式实现,存在一个完备性问题。
这套解决方案在业界使用相对比较广泛,阿里内部有飞猪的 Flugy 方案,外部有字节的 ORYX 方案,还有一套是微信小程序本身的 Flutter 方案。
思路 3:遵循 Web 思路,扩展对接 RenderObject
第三个思路是越过了 Widget 这层,直接在 Render Object 这层去做对接,这种方案就相当于还是在 Dart Framework 里面去实现 WebAPI、CSSOM,在后面的类似于前端渲染 Render Tree 的步骤,将其渲染成 Flutter 的 Render Object Tree。
这一方案的优势有两点,一是去除 Dart Framework diff 流程,性能得到了一个提升,二是直接对接到 Dart Framework 的 Rendering 层,样式实现自由度变得更高了,可以实现与所有的 CSS 属性无缝对接,完备性问题迎刃而解。
同时这一方案也存在两点劣势,首先,其改造成本较 Widget 层对接更⾼,其次的话, Rendering 这一层在 Dart Framework 里处于中间位置,也就是说当使用了 Flutter 内部的数据结构,未来 Flutter 升级时中间的 API 完全有可能变更,将导致升级成本变得非常高。
思路4:遵循 Web 思路,直接对接 引擎 层(自绘版 RN/Weex)
这一思路是直接对接 C++的 Flutter 引擎,当然中间的 Framework 是不可缺失的,将 Flutter 引擎暴露的能力转化成前端的 Web API。既然要实现 Framework,自然不需要依赖任何的 Dart 能力了,可以直接把 Dart 摘除,用 C/C++来实现。这一方案存在三点优势:
直接对接最底层的 Flutter 引擎层,稳定性较好
去除 DartVM 及 Framework,包体积大幅缩减
JS 可以直接跟 C++通信,跨语言通信复杂度降低,性能提升
劣势则是手势、事件、绘图这些 API 都需要自行用 C++重新去写一遍,复杂度跟成本相对较高。这套方案目前阿里内部淘系技术部正在尝试。
从一个前端开发者的视角来看,其实我们真正需要关注并不是底层 Web 跟 Flutter 标准的对接到底该采用哪一套的方案,更应关注的是这套方案能不能对接到子集标准。在对接到子集标准的情况下,这些方案之间能够实现平滑迁移,这样无论是用 Dart,还是 JS,抑或是 C++来实现,在 Widgets、Rendering、Flutter 引擎哪一层切都没有问题。
统一跨端研发框架
从阿里内部来看,在 W3C 子级标准之上建立的研发框架,类似像 Rax 或者 Remax 之类的跨端方案,虽然也提供了对接底层多个渲染容器的能力,但是对于每个渲染容器都是需要重新打包的,复杂度和维护成本非常高。
在考虑到整个集团内使用场景覆盖度以及目前覆盖业务单元数量的情况下,阿里选择了 Rax 作为统一研发框架和标准进行推进。凭借着 Driver Spec 机制,Rax 同时支持了 Webview、Weex、AJX、Flutter 的渲染能力,具体的实现方式可以理解为 Rax 框架底层定义一套抽象的 API 结构,每一个底层引擎只需要去适配 Drive,当设定的 API 全部实现就可以驱动上层框架在多个渲染容器中运行。
但这也存在一个问题。底层渲染容器虽然基本都是遵循 Web 的标准设计,但是大多标准都是不统一的,这就导致一个很关键的问题,即最终可能只能选取子集标准作为适用方,如果子集非常窄,那研发将变得非常受限。
上图是小程序的研发链路,目前 Rax 采用的是编译式的方案,通过构建时编译的方式将 Rax DSL 直接编译成 axml,但由于 Rax 的 DSL 跟小程序的 DSL 都是非完备的,当把一个非完备的 DSL 转成另一个非完备的 DSL 一定会有很大的限制,这就导致开发中很多特性无法使用,比如说如果用一套 Rax 代码编一个小程序,就不能写高阶组件,否则编译失败。
为了解决这个问题,阿里把小程序的对接方案改成了一个运行式的方案,把底层小程序提供的 API 封装成一套 Web 标准子集——可以理解成在小程序的框架之上提供一套标准规范的封装,在这之上 Rax 代码就能够通过 driver-dom,实现上图这样一条链路。
再往前想一步,当把标准化容器统一到一套 Web API 上时,所有业务开发都对接到子集标准,对于 Rax 这套研发框架,未来可能一次构建其中一套 driver-dom 就可以实现全平台的一个适配。同时子集标准可以隔离前端的研发框架和底层渲染容器,未来有望对接更多的研发框架。
跨端配套基础设施
如何保证标准实现的有效性?
解决这一问题的思路是自动化测试,包含 UI 自动化、API 测试以及性能、稳定性相关指标。阿里的自动化测试框架能够向上层提供数据,帮助发现当前的容器标准的问题和现状,然后敦促各个容器的接入方去做改进,同时这些数据也支撑了前端同学的 CanIUse 以及 IDE Plugin,帮助他们提升研发效率。
在底层渲染容器不统一的情况下,如何拉齐不同渲染容器之间的性能指标?
阿里的解题思路是提供两个核心的时间点,一个是白屏时间(在首页进行渲染操作的时间点),一个是首屏渲染时间(渲染过程中首屏所有大图片首次加载完成的时间点),参考了 W3C-LCP 、UC-U4 的标准,标准只是一个体感指标,本身跟底层实现无关,它只是一个体感指标,我们可以让各个容器去实现这个标准,采集对应的数据。但因为容器没有办法定制,那对于前端页面投放到段外的场景,这套标准要如何实现兼容?阿里提供了一套基于 Performance Observer 跟 Mutation Observer 的近似计算方案,每次 dom 变化时就收集对应信息,以上报数据的方式来实现 Web 端的兼容。
Hybrid API 如何像 Web API 一样实现兼容适配?
首先统一了一套前端跟客户端的调节协议——MethodChannel,在这个基础之上,阿里拉通了集团内大概 50 多个的 App,统一了一套 Hybrid API 标准(包含 55 个通用的 API),同时提供了配套的数据监控、CanIUse 等工具,保证大家在接入这一套 JS Bridge 的情况下,在不同端内都能够实现平滑的切换。
跨端展望:自绘、多中心化、大割裂
从 Flutter 开始我们就认为自绘渲染可能会成为未来所有跨端技术的标配,它重点解决的是双端一致性问题,但是从发展的角度来看,实际上自绘能够降低 OS 的限制。在 Google 的战略 Flutter 是强绑了 Future OS 的,如果将 OS 比作一张画布,自绘提供的能力就是在任何一张画布上都能够把上层的 Web 技术、Native 技术、动态模板技术、Canvas 技术完整的进行实现。其带来的最大价值就是未来不管是否会出现新的 OS 或者业务场景,依然可以实现客户端基础能力的快速搬迁,不需要进行重复建设。
其次,从业务视角来看,今天的互联网正在变成多中心化。在 PC 时代,Web 是真正的互联互通,移动时代下流量被分在不同的 App 端内,逐渐演变成一个多中心化的时代。这会带来两个变化,一是目前已经有所显现的流量坚定,二即每一个中心化 App 都有能力去定义规范和规则。在 2014、2015 年的时候很难想象会出现类似小程序的方案,因为它的流量结构体系不太可能让人愿意去花费巨大成本适配它的解决方案,在今天小程序却已经司空见惯,而且所有开发者不得不去适配兼容不同的标准。
那中心化会衍生出什么问题呢?今天我们能够通过 Terror、UnitApp、Rax 这些方案抹平不同的小程序之间的差异,实现一套代码无缝装载到多个 App 端内。但深思一下,如果这种发展趋势,不同端的技术选型架构模式可能会出现越来越大的分歧和差异,当到了某一个临界点时,我们会发现一次开发多端适配获得的效率优势完全没有兼容性带来的成本高,这将可能导致一个大割裂——未来团队的组织架构不再是前端开发工程师、iOS 开发工程师、安卓开发工程师,而是微信小程序开发工程师、字节小程序开发工程师、阿里小程序开发工程师。
所以说再看这两个数据,今天 JavaScript、TypeScript 等语言的开发者全球超过 1000 万,这波开发者是全球最大的语言开发者,就是我们单从一门语言来说,JS 是当之无愧的世界第一。
基于此,很高兴能够看见 2020 年底小程序在 W3C 的规范组正式成立,这也表明还是有很多开发者愿意为了更好的标准化、更互联的一个 Web 世界去做努力。也希望每一个前端的从业者能够更多地关注标准、思考标准、推进标准,助力 Web 技术实现更好地互联和互通,帮助 Web 技术赢下移动互联网之后下一个设备平台。
嘉宾介绍:张舒迪 ( 圣司 ),飞猪用户前端及数字化经营团队负责人,致力于移动前端、中后台技术基建及在旅行场景的业务落地;阿里前端委员会跨端技术方向负责人,着力推进跨端容器器及研发框架标准化建设,完善配套设施。
今年 5 月 29-31 日,QCon 全球软件开发大会将在北京举办。大会汇聚上百位演讲嘉宾,同时设立 30 余个热点技术专场包括 Serverless、Flutter、DDD、音视频、云原生、智能金融、大数据、数字化转型、人工智能等,内容源于实践并面向社区。【扫码】或点击【阅读原文】了解更多。
目前会议限时 9 折,购票立减 880 元,团购还有优惠!
☞ 有任何问题欢迎联系票务小姐姐 Doris:17310043226(电话同微信)
评论