在2016年4月份的QCon上,阿里巴巴资深总监,淘宝移动平台及新业务事业部、阿里百川负责人庄卓然(花名南天)宣布阿里移动端跨平台开发框架Weex开始内测,并将于6月份开源。在QCon的第二天,阿里技术专家徐凯(花名鬼道)和阿里前端开发专家赵锦江(花名勾股)向参会者做了《Weex——灵活的移动端高性能动态化方案》的演讲,对这一技术方案进行了详细的剖析。
以下为演讲内容的整理:
昨天南天宣布Weex启动开源内测,截至到今天中午,我们统计申请内测用户突破1400人,大家的热烈程度远远超过我们的设想,非常感谢大家支持。
在我们对移动开发最佳实践的思考中,我们认为移动开发的未来是更平衡的方案,一定是性能和动态性兼得。第二个,它一定是开放互联的,PC端一直也是这样的,也是非常好的状态。我们觉得移动互联网将来肯定也是基于更大众化的技术体系,没有平台之间的隔阂,简单直接易用,这是我们最希望看到的。基于这些设想,我们有了Weex方案。
Weex是从去年双十一的时候第一次在我们正式产品中使用,承载了双十一主会场的工作。有人会问,Weex是不是除了做主会场别的地方就比较吃力呢?从去年双十一到现在,包括我们自己的尝试和阿里内网做开源内测活动,大家也贡献了很多内容,包括昨天Keynote演示的僵尸动画,扫雷、计算器都有,各种丰富场景的东西都可以通过Weex做出来,不仅仅是做主会场的技术方案。
对移动端开发模型的理解
我们谈谈Weex团队对移动端开发模型的理解。
今天绝大多数移动端APP是这样一个最佳实践,首先把移动端所有界面拆分成各个page,中间有一个路由的控制逻辑。同时我们需要移动端各种各样丰富的能力,通过API的形式提供给开发者。这是我们认为一个比较理想的开发模型。
从开发模型来讲,我们比较倾向于通过标准化的一些东西,包括HTML、CSS、JS这些前端非常快速易用好学的语法作为一个开发体验,提供给开发者。这里强调一下,我们语法设计尊重了Web标准,包括核心源代码都是从Vue.js——一个非常优秀的MVVM前端框架来的。我们的开源内测同步在海外通过Vue.js的Twitter等途径进行宣传,得到了非常热烈的反响,短短一天时间内,老外们的关注度和热情也是出乎我们的意料。有些人非常兴奋和激动,想知道什么时候看到源代码,和我们联系,我们觉得也是值得高兴的一件事情。
Weex的组件化与DSL语法
Weex编写的页面天然的支持组件化,首先,我们的界面可以是一个组件化的,把一个复杂界面分成每个组件,刚才演示的都是简单的组件,每个组件都可以看成是一段template,style,script,放到模型里,对应到界面的结构,样式细节,行为定义。在view里面我们倾向于把数据和视图当中需要展示和需要有动态变化的部分做一个数据绑定,绑定之后我如果想更改界面的话,通过改变数据就可以做到。这是从model到view非常顺畅的控制逻辑和代码方式,这也算是Weex上层语法设计的基础。如果大家做的界面比较复杂,可能有更多细节,或者做更多分解,我们需要从整体上对整个界面以模块为单位作为拆解,对每个模块做定义,如果界面足够复杂,可以先拆成组件,再把每个组件具体内容进行定义。定义方式就是通过结构、样式和行为角度对它进行定义,通过有机方式把这些组件结合起来,完成页面开发。
关键语法简述。首先看看template,大概有几个元素。它首先是virtual DOM tree展示,包括事件绑定,组件跟组件之间还可以嵌套,还可以有子元素,这是整体template结构。再往下是style,一方面可以把共用样式抽样出来,另一方面可以让template结构更加清晰,不至于陷入到整个具体样式描述当中去。我们在这边会做一些收敛,我们只支持了单个class的selector写法,主要从性能角度考虑。传统的css可以理解为是一个N对N的数据库,匹配过程非常复杂,性能也得不到非常好的保证,我们为了保证性能,我们把selector约定在单个class,性能可以保证。
另外,我们的样式天然默认的就是scoped,大家可以放心定义各种各样的classname,不担心和其他组件相冲突,全局冲突是CSS“七宗罪”中的一个,其实这也是我们非常重视的,所以在实践上我们把它做到了scoped。
其他的,可以做一些展示的控制,比如if、repeat刚才演示中也提到了。刚才没有演示到的这个很特殊,append,在性能不是那么好的Android下,界面加载过程用户是可感知的,不是一瞬间做到的。我们加这个值可以让你精细化展示界面的颗粒度,如果上层做了append等于tree的话,里面一系列东西会做一次性的加载,这是从性能优化角度做的特殊设计。再是id,我们可以通过在这里面写id拿到这个值,把它当作参数传给API做处理。
我们现在已经支持的组件,除了刚才演示的div空白容器、图片、文本之外,我们还支持slider:一个性能比较好的滑块组件,还有list,性能上自动做内存管理和资源管理的组件,把性能和帧率各方面都做的比较好。还有input,输入框我们是最近才做的,也是刚支持的,可能还有试验性阶段的小东西。在这个范围之外,业务方可在上层横向扩展,稍后会有具体介绍。这是template和style部分的介绍。
样式部分我们支持flexbox,非常灵活通用便捷的布局方式,有了flexbox,只要你的界面可以拆分成豆腐块的,都可以用flexbox来做,同时我们还做了fixed和sticky这两个特殊的布局,sticky意思是如果有一个列表分类,比如联系人ABC字母滚到屏幕外,会停在最上面,那个效果就是sticky,当你划走它就会跟着走,在各种手机应用当中是一个比较常见的东西。同样,更多的样式每个组件也可以自己定制,非常灵活。
从事件角度,click是基础事件,change在表单的值改变和滑快的第几帧改变时都会有,同时我们加入了appear和disappear,当我通过任意操作进入屏幕区域内,会触发appear事件,出来以后会触发disappear事件,非常适合用在一些lazyload之类的逻辑场景。这些事件也可以在各自组件中做横向扩展。
Script部分刚才例子也提到了,主要是viewmodel设计,最主要的是data和methods,值修改之后相应数据绑定的值也会发生改变。除此之外我们提供了生命周期的方法,创建的时候,数据监听完成的时候,渲染完成的时候,你只要把这三个方法同样写在data和methods下面。还有原生 API,刚才演示的时候也出现了,这里不多介绍。
组件化搭建很复杂,通过定义子组件,比如我上面有一个foo组件,通过foo标签就可以把foo嵌入到别的组件中来,数据传递的话就可以在foo组件中写a和b,foo元素就可以通过这种方式传递给子元素,然后进行处理。再是组件中间的通信,也是事件机制,每个组件可以通过和off,对自定义事件进行监听和解绑定,想触发事件也有三个方法:只传给自己、dispatch向上冒泡给所有父组件、$broadcast广播给所有子组件,这些设计和Vue非常相近的,做到组件之间的通信。
除了刚才介绍的这些特性,我们未来还会提供更丰富的、相信也是开发者需要的、平时开发中会碰到的场景,更丰富的表单,还有更好的动画展示,包括复杂手势场景。在这方面,无论是性能还是开发体验、最终效果都能够非常好,这是团队正在努力在未来提供给大家的。同时我们希望收集和分享更多相关素材,做出更多工具,提供更好的开发者体验给大家。
更多的内容,包括刚才演示的Playground App都可以通过我们的官网找到,现在处在开源内测阶段,大家提交申请,通过以后可以访问仓库,了解更具体的内容。
Weex的工作原理
这张图大家都不陌生,前面也提到了,勾股说的主要是DSL这层。再往下到了Virtual DOM和Render层;H5,我刻意把它用不一样的颜色标出来,想让大家知道我们设计之初就考虑到希望在三端上能够展现,所以这个地方稍微加亮一些。
我们把刚才这张图再稍微展开一下,最上面是我们的DSL,我们一般叫Weex文件,通过transformer这层,部署到Server,服务端就完成了。大家不用担心我们的转换是不是有性能问题,因为这在服务端就已经完成。到了客户端,第一层是我们的JS-Framework,最后到RenderRengine,再往下看,左边是我们的DSL文件,右边是转换出来的jsbundle,在DSL中的template会将我们的类型和子节点都表示出来,将classList转化成基本语法约定,包括自变量的转换。最后是脚本,脚本基本上是直译过来。输入是Virtual DOM输出是native或者H5 view,还原成内存中的树型数据结构,再创建view,把事件绑定在view上,把view基本属性设上去。虚线是在native上经历一个过程,在H5上相当于把这个事情交给webkit LayoutEngine去做,把所有元素尺寸和位置重新调整。整个这张图基本上讲清楚了Weex Render流程,我们会分三个线程,不同的线程负责不同的事情,让JS线程优先保障我们的流畅性,未来我们会有更多的技术文档,比较细节的放出来。
Weex的性能、扩展以及可用性
下面是在整个Weex架构上比较关键的点,这些可能是我们目前关注度最高的,包括性能、扩展以及可用性。
首先是性能,我们内部有这样一个压测页面,我们同学把benchmark放在Playground,大家如果下载是能够看到的。在我们内部做压测的时候调到三千个节点,大概10屏,一屏有三个卡片,一个卡片有100个节点左右。我们看一下数据,第一个性能对比是我们的加载时间,同样一个页面1300、1600,也不算特别大,20%左右,帧率大概差开一帧,scroller差不多,内存这块会好一点,因为我们这边用了recycle view,会好一些。再往下是CPU,静默CPU消耗,还有运行过程中CPU的峰值。静默CPU接近0点几,我们不做16毫秒的轮循,如果做16毫秒轮循CPU会更高一些。
这是一个真实业务数据,3月份页面上线之后我们看了一下,这张页面是一个活动,3月份新风尚的活动,这个活动页面没有用List,没有特别做内存对比,这两个设备定义为低端机,帧率差压比较明显,无论是数据还是实际中的体验,流畅性大概是这样的差距。我们说性能往往都会提到帧率、加载时间,但往往会忽略一个事情,Native UI开发中通常没有JS资源在服务端加载,Weex以及类似动态化方案有一个副作用,我们有一个JS必须从服务端下载,我们把JS内置到客户端里,免除下载的问题,这里涉及到一整套的策略。我们内部有一套机制,之后会把这套机制作为独立的技术产品开放出来。
下一个是我们的兼容性。兼容性不只是对Weex,对偏内核型项目都会有这个问题,举一个Weex例子,第一排是我们的业务代码,再往下看,上面两次变迁,一直到客户端,整个场景会变成N的立方。举一个具体数字,我的业务代码改了三个版本,(英文)三个版本,最后会有三的立方27个场景。兼容性是我们一直重视的问题。我们做了几件事情,首先单测保证,包括JS和H5的单测,保证最最基础的UT本身带来的含义。第二个是JS单测环境,我们一般会将(英文)跑在(英文环境下,但和JS安全还是有差异。再往下是自动化工作,这块工作细分也可以分成两块:一块是我们针对截图比对,比如我们同学会说我们设置了很多各种各样细节属性,怎么说你渲染出来的就是你实际想要的,通过API级别的效果不是很好。所以这种我们会通过截图,将最终产生的结果和我们意料中的结果进行图形比对,比较老的成熟的内核上面做的比较成熟,也会有一些借鉴。另外是layout results,相当一部分,包括model,包括其他的布局类的,其实我们完全可以通过一个元素,最终它的宽高,左上角的点,通过基本的信息,让它完成测试的过程。所以我们经过这两块工作,一旦成熟,我们会尽快放到上面。
再就是扩展性,我们先回顾一下这张图,前面也有提到,目前Weex给大家直观的感觉是可以用Weex写很多页面,有一个路由机制,内部叫导航,帮助你将页面进行串连,我们提供很多features,由这样的形式构成Weex大家所看到的一个结构。细分来看,如果你扩展一个component,特定的一些方法,使用anotation标识输入输出参数。这是一个module,在DSL上看到的是API,底层就是module。如果扩展module也是一样的,这是很简单的跳转,基本信息带上去,实现业务功能,一个module就完成了,很简单。
这是路由,整个路由在APP Framework中只是一个环节,所以接下来的规划还是有许多东西需要做的,单独看components这块,包括前面两个,再往下是lifecycle考虑,再是动画跟手势,这块我们觉得都是最基础的东西。再往下是全局的多个Weex容器之间通信机制,数据存储、网络,包括下面涉及到的一堆传感器,包括基础的FS,还有偏业务类的东西,整个东西都有同步在做,但现在的工作集中是在这块。回到刚才的老问题,如果我们开放一个module,上层提供API,中间提供adapter,如果提供自由实现就将默认的覆盖掉,比如手淘里面(TBxxx),把默认页面覆盖掉(WXxxx),对大家来说在已有能力增强,或者是增加新的组件,或者是新的module上,目前已经达到这个状态。
最后是我们的可用性,前面说的比较多,这块秀几张图就好了。这是我们的工具链,红色代表完成的,黄色是五月份、六月份就会完成,在六月正式开源之前。剩下一些东西是我们内部正在讨论以及会安排时间逐步完成的东西,这些都是工具。我们首先给大家提供一个playground,可以扫码,也有自带的examples。第二个是调试工具,chrome dev tools常见的功能里面都有。再是脚手架,大家如果只是玩玩的话用playground就可以了,如果自己做一个独立的APP,你要用Weex做的话我们也会给你提供脚手架。我们的规划中独立项目,不是最终的名字,最终会有一个类似APPHub的工具。包括信息察看,在界面上展示结构。这是刚才提到的例子,这个是playground里面的,虽然截图是iphone效果和android是完全一样的,已经用Weex现有功能做出比较好玩的组件库。然后是我们的文档,包括项目guide、reference、toolchain,细节我不多说了,大家可以去看看。
Weex的集成方式
目前Weex有三种集成方式:
-
全页模式
o 目前支持单页使用或整个app使用weex开发(还不完善,需要开发router和生命周期管理)这是主推的模式,可以类比RN。 -
Native Component模式
o 把weex当作一个iOS/Android组件来使用,类比ImageView。这类需求遍布手淘主链路,如首页、主搜结果、交易组件化等,和业务同学沟通下来这类Native页面主体已经很稳定,但是局部动态化需求旺盛导致频繁发版,解决这类问题也是Weex的重点。
o 这也涉及到如何让Native同学快速上手“准Web”开发,有意思的话题,大家多给些建议。 -
H5 Component模式
o 在H5种使用Weex,类比WVC。一些较复杂或特殊的H5页面短期内无法完全转为Weex全页模式(或RN),比如猫超、互动类页面、一些复杂频道页等。针对这个痛点我发起过WVC项目,并在实际业务中验证了这样的想法:在现有的H5页面上做微调,引入Native解决长列表内存暴增、滚动不流畅、动画/手势体验差等问题。
o WVC将会融入到Weex中,成为Weex的H5 Components模式。
这3种模式几乎涵盖了淘系业务上的动态化需求(针对Native)或体验提升需求(针对H5)。更有趣的是这3种模式的技术基础是一致的,这非常重要,意味着:业务方可以使用Native或H5 Component模式 解决实际的业务痛点,同时平滑过渡到Weex全页模式。期待Weex成长壮大到AppFramework的那天。
最后是我们过去双十一到现在大概五个多月时间做的一些事情。首先我们做了原型版本,再将原型版本独立出独立客户端可使用的SDK,扩展样式和布局,将基础的component做了扩展,这两个月集中在工具,还有open source上的工作,最后是六月底就会开放出来。
阿里百川(baichuan.taobao.com)是阿里巴巴集团无线开放平台,通过“技术、商业及大数据”的开放,提供移动场景下的高内聚、开放式、行业领先的技术产品矩阵、成熟的商业组件和完善的服务体系,帮助移动开发者快速搭建APP、加速APP商业化进程,全方位赋能移动开发者及移动创业者。