Weex详解:灵活的移动端高性能动态化方案

原文地址:http://www.infoq.com/cn/articles/introducing-weex

 

 

在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元素就可以通过这种方式传递给子元素,然后进行处理。再是组件中间的通信,也是事件机制,每个组件可以通过$on$off,对自定义事件进行监听和解绑定,想触发事件也有三个方法:$emit只传给自己、$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的立方。举一个具体数字,我的业务代码改了三个版本,JS Bundle三个版本,weex三个版本,最后会有三的立方27个场景。兼容性是我们一直重视的问题。我们做了几件事情,首先单测保证,包括JS和H5的单测,保证最最基础的UT本身带来的含义。第二个是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有三种集成方式:

  1. 全页模式
    o 目前支持单页使用或整个app使用weex开发(还不完善,需要开发router和生命周期管理)这是主推的模式,可以类比RN。
  2. Native Component模式
    o 把weex当作一个iOS/Android组件来使用,类比ImageView。这类需求遍布手淘主链路,如首页、主搜结果、交易组件化等,和业务同学沟 通下来这类Native页面主体已经很稳定,但是局部动态化需求旺盛导致频繁发版,解决这类问题也是Weex的重点。
    o 这也涉及到如何让Native同学快速上手“准Web”开发,有意思的话题,大家多给些建议。
  3. 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上的工作,最后是六月底就会开放出来。

posted on 2016-05-03 09:39  zoucaitou  阅读(1946)  评论(0编辑  收藏  举报