对无线电商动态化方案的思考(二) #14

Open
Jinjiang opened this Issue Nov 18, 2015 · 29 comments

Projects

None yet
@Jinjiang
Member

上一篇谈到了我对无线电商动态化的理解,并简单提到了我们自己提出的技术方案:Weex,今天就来详细介绍一下 Weex

一句话介绍

Weex 是一款轻量级的移动端跨平台动态性技术解决方案!

几个特点

轻量

体积小巧,语法简单,方便上手

可扩展

业务方可自行横向定制 native 组件和 API

高性能

快速加载,快速渲染,体验流畅

其它

  • 拥抱标准:基于 Web 标准设计语法
  • 响应式界面: 通过简单的模板数据绑定轻松解决数据和视图的同步关联问题
  • 多端统一:iOS、Android、HTML5 多端效果一致,撰写一次就可以轻松达到跨平台的一致性,无需针对多套平台单独开发,省时省力
  • 复杂逻辑描述:动态性不只体现在展示效果的动态性上,更体现在可以实时调整复杂的数据处理方式和逻辑控制方式
  • 组件化:组件之间通过 webcomponents 的设计完美的隔离,并可以通过特定的方式进行数据和事件的传递
  • 生态&链路:我们为 Weex 的开发者和使用者在不同维度上提供了各式各样的工具和平台,包括代码打包工具、开发者调试工具、部署平台、Playground、经典案例、入门指南和详尽的文档等。你不是从零开始,你也不是一个人在战斗!

如何工作

1. 本地组件开发

首先,我们像开发 webcomponents 一样,把一个组件分成 <template><style><script> 三部分,刚好对应一个组件的界面结构、界面样式、数据&逻辑。

components

图:组件化开发思维和书写方式

细节1:顺便说一句,这也是我们认为描述界面的最佳实践。

代码示例:

<template>
  <container style="flex-direction: column;">
    <container repeat="{{itemList}}" onclick="gotoDetail">
      <image class="thumb" src="{{pictureUrl}}"></image>
      <text class="title">{{title}}</text>
    </container>
  </container>
</template>

<style>
  .thumb {width: 200; height: 200;}
  .title {flex: 1; color: #ff0000; font-size: 48; font-weight: bold; background-color: #eeeeee;}
</style>

<script>
  module.exports = {
    data: {
      itemList: [
        {itemId: '520421163634', title: '宝贝标题1', pictureUrl: 'https://gd2.alicdn.com/bao/uploaded/i2/T14H1LFwBcXXXXXXXX_!!0-item_pic.jpg'},
        {itemId: '522076777462', title: '宝贝标题2', pictureUrl: 'https://gd1.alicdn.com/bao/uploaded/i1/TB1PXJCJFXXXXciXFXXXXXXXXXX_!!0-item_pic.jpg'}
      ]
    },
    methods: {
      gotoDetail: function () {
        this.$openURL('https://item.taobao.com/item.htm?id=' + this.itemId)
      }
    }
  }
</script>

显然这些代码是不会被 native app 识别的,我们要想办法让这些代码可运行。所以我们同时做了三件事:

  1. 在本地用一个叫做 transformer 的工具把这套代码转成纯 JavaScript 代码
  2. 在客户端运行一个 JavaScript 引擎,随时接收 JavaScript 代码
  3. 在客户端设计一套 JS Bridge,让 native 代码可以和 JavaScript 引擎相互通信

所以紧接着第二步,就是用 transformer 对代码进行转换,变成客户端可运行的 JavaScript 代码

transformer

图:本地开发时的 Weex Transformer 工作原理

其实本地开发还有一点很重要,就是把复杂的界面通过组件化的方式进行分解,并合理的建立组件之间的组合和调用关系。

最终,我们把简单组件组合成复杂的界面,并通过 transformer 打包成一个完整的程序包 (主体是一段 JavaScript 代码)

细节2:由于 Weex 组件的开发和 Web 组件的开发非常接近,但是对标准的支持范围和一些细节是有不同之处的,我们会贴心的在 transformer 里加入了一些友情提醒,帮助大家回避常犯的书写错误。

2. 客户端渲染

上一节已经提到了,我们在客户端会运行一个 JavaScript 引擎并且有 JS Bridge 通信机制。这里再介绍具体一些:

native 渲染和 JavaScript 引擎之间,主要进行三类通信:

  1. 界面渲染,单向 (JS -> native):这毫无疑问,JavaScript 引擎需要把界面的结构和样式告诉 native 端,这样我们才能得到 native 级别的终极界面效果
  2. 事件绑定与触发,双向:在我们的客户端技术方案中,native 端只负责界面渲染和非常薄的事件触发层,事件的逻辑处理都会放在 JavaScript,这样我们就具备了复杂数据处理和逻辑控制的动态性可能。JS 告诉 native 需要监听的交互行为,而当用户产生对应的交互行为时,native 端会把交互信息回传给 JS
  3. 对外的数据/信息请求与响应,双向:JS 引擎在处理特殊逻辑时,难免需要向服务器请求数据、或请求本地的系统信息和用户信息、或调用 native 的某个功能,这个时候也会通过 JS Bridge 进行请求,native 收到这些请求之后,也会在必要的情况下通过 JS Bridge 把信息回传给 JS 引擎

runtime

图:客户端运行时的 JS 引擎和 native 之间的通信

再加上外层对 Weex 实例的管理,整套机制就可以顺畅的工作起来了

细节3:native 端渲染的时候,我们以图片和文字的形态为主,并大量依赖了标准的 CSS 样式进行细节的渲染

细节4:我们把框架层面的 JS 代码全部提前放在了客户端本地,并提前运行做好准备。这样本地生产的 JavaScript 是非常小的,网络传输的代价也非常低,而在客户端运行的初始化成本也非常低。整条链路都和界面打开速度息息相关

细节5:我们在 JS 处理界面逻辑的过程中采取了数据监听+依赖收集的策略,既没有通过脏检查,也没有通过全量 diff Virtual DOM 树的方式,因为通常在移动端,数据变更都是非常小量的,经过我们的实践,这套方案完全可以应付移动端日常的动态性界面需求

virtualdom

图:Virtual DOM 的数据绑定和更新机制

细节6:我们对业务上通用常用的组件进行了封装,并且暴露规范化的类型 (标签名)、特性、样式、事件、上下级约束等维度的定义。这样所有的业务界面都可以用这些基础的组件搭建而成

细节7:我们对业务上通用常用的 API 进行了封装,并且暴露规范化的 JS API

3. 服务端部署

我们在服务端提供了基础的程序包发布,给每个程序包一个特定的 page id,然后为客户端提供通用的服务,通过 page id 获取程序包,这样本地开发、动态实时部署、客户端动态化渲染和逻辑处理就完美的串联在一起了

细节8:实际上,除了界面本身可以动态化之外,客户端的 JS 引擎的代码、还有部分 native 的实现,我们也准备了相应的动态化机制,也就是说客户端的动态能力本身也是具有动态性的

4. 浏览器端渲染

我们还会面对这样的场景,就是一个客户端的业务,会通过微博之类的渠道进行转播和推广,当用户手机里刚好安装了手机淘宝客户端,那么会直接“拉起”客户端进行相应的界面展示,如果没有装手机淘宝,则需要在浏览器里展示一个相同或接近的界面。自然 Weex 技术方案支持的业务也有这样的需求。所以我们同时提供了 HTML5 版本的技术方案,同一份 JavaScript 程序包,可以同时通过客户端的 JS Bridge 渲染成为 native 界面,也可以通过浏览器渲染成为 web 界面。我们的做法也非常简单,就是把 JS Bridge 背后的 native 处理逻辑同构成了 HTML5 版本。然后发布这样的一个页面。

html5

图:HTML5 浏览器端的架构实现

细节9:我们能够同构 HTML5 版本和 native 版本,主要归功于我们在 JS Bridge、组件定义、API 定义方面的高度抽象——当然 HTML5 的版本在性能和体验上确实有一定的劣势,并不是最理想化的效果,所以核心的主战场还是客户端,这也和目前的移动互联网的形态相吻合

5. 周边

为了方便 native 界面的调试,我们还提供了配套的开发者工具,稍后会有更多介绍,同时我们的上层配套可视化编辑器和装修工具,也在紧张的研发当中。

综上所述,整个 Weex 的工作原理大致可以用一张图来表述:

workflow

## 回看 Weex 的几个特点 ### 轻量

我们致力于把开发体验、网络传输的大小、运行时的开销控制做到极致,并且尽可能的降低多端适配和优雅降级的成本

横向可扩展

我们对组件的定义和业务功能预留了很好的横向可扩展能力,这也业务方可以自由定制属于自己的 native 组件和 API,从而在后期可以通过实时发布不同的程序包来进行动态化控制。同时也因为它的横向可扩展性,Weex 的核心可以非常小,非常易于融入现有的无线技术体系

高性能

我们在网络传输、实例初始化、JS 运算、native 渲染能力等方面做了非常针对性且深入的优化,尤其是针对中低端安卓机,不论是加载时间还是运行时的流畅度,都比之前的方案有质的飞跃。我们对 CPU、内存、帧率、首屏渲染时间等核心性能指标也一直保持高度的关注,也建立了相应的线上监控和数据统计机制。而更多可优化的空间和方案我们还在不断的进行优化尝试。

下图是今天凌晨旧金山 QCon 上 Weex 技术方案的首次公开分享中的一页性能表现对比图,大家可以感受一下:

总结

这就是 Weex,如上一篇文章所介绍的:

  • 致力于移动端
  • 能够充分调度 native 的能力
  • 能够充分解决和回避性能瓶颈
  • 能够灵活扩展
  • 能够多端统一
  • 能够优雅“降级”到 HTML5
  • 能够保持较低的开发成本
  • 能够快速迭代
  • 能够轻量实时发布
  • 能够融入现有的 native 技术体系
  • 能够工程化管理和监控

目前 Weex 还在努力达到更高的性能、更高的扩展性、更低的开发成本、更完整的生态和工具链,也同时尝试接入更多的业务,体现出它的更大的价值。已经有很多业务方迫不及待的在和我们主动取得联系了,未来我们希望 Weex 能够逐步在集团内开放试用,并最终走向开源。

另外整个技术方案还有很多值得分享的东西,比如 transformer 的实现、组件和 API 的设计思路等,我们会再做针对性的分享和介绍

(马上更新第三篇ing)

继续阅读:

@zzbo
zzbo commented Nov 18, 2015

当时以为是讲react呢。

@wssgcg1213

很有诚意 期待WEEX的开源

@myheartwillgoon

给数学老师点个赞!!

@Gaohaoyang

给跪了,真牛逼。

越看越兴奋!

@pfan123
pfan123 commented Nov 18, 2015

good

@KavinHan

支持~期待开源+1

@miniflycn

作为业务狗,的确有些惆怅。我们团队其实早在年初就开始实践这件事情了,可惜完全没有时间去实现全端同构的构想。🐶

@GavinHans

very good .

@ouvens
ouvens commented Nov 19, 2015

最近一直在炒webcomponent,并基于其思想自己设计框架,但是很多人并没有理解webcomponent的规范的含义和未来的规范趋势,只是借鉴了它的设计思想造自己的轮子而已,设计的时候可以更注重下什么是规范~

@RubyLouvre

HTML与JS规范不是向来被大家践踏的吗?!而且web components是谷歌自己率先提出来的,而更早的由微软提出的html components规范其他厂商都不想支持,没有理由让微软去支持它

@tcdona
tcdona commented Nov 19, 2015

@ouvens 那规范自己快挂了

@iphone-andy

听起来很牛逼的样子

@happypeter

“三端大统一”的时代,是不是 ios 和 andriod 开发者都要考虑转学 js 了?

@floraluo

看不明白这是啥子,是说以后开发app都不用java和ObjectC了吗?像cordova那样 暴露接口给js用吗????

@myheartwillgoon

@floraluo 混合模式开发,纯native模式业务更新不方便,纯js体验没native好,外部通用框架对自己的业务太重,按灵活性与体验感寻求适合自己业务的平衡点.

@daemonchen

mark

@CodeDaraW

最后一个图表,新技能get

@yutingzhao1991 yutingzhao1991 referenced this issue in yutingzhao1991/github-blogs-weekly Nov 22, 2015
Open

文章更新 [ 2015-11-15 - 2015-11-21 ] #11

@Grainspring

关注Virtual DOM与native Android/IOS View的关系,有丰富的ListView支持嘛。还有JS引擎运行的线程与UI主线程是同一个嘛

@InsCake
InsCake commented Nov 23, 2015

你这个图是ipad pro画的吗?

@xiekw2010

考虑过react的三端统一吗?我意思react component在最上层有一套通用的组件,供web,iOS,android调用

@Jinjiang
Member

@InsCake FiftyThree 我觉得 Apple Pen 是抄他们的

@Jinjiang
Member

@xiekw2010 之前也考虑过,这是个上层 DSL 的设计问题,最近已经有同学在跟我们探讨这个问题了,不过总体上我们对 JSX 的设计还是持观望态度

@qqqzhch
qqqzhch commented Dec 12, 2015

回避性能瓶颈!!!!说的太好了
现在很多人一说性能优化就要和某个性能瓶颈做死磕,
海能写一堆方法论出来
BUT客户端千变万化的环境,死磕到猴年马月才能解决完呢

@zhangchunsheng

我们在开发App时,发现运营需求越来越多,配置越来越灵活,选择React是唯一解决方案,期待Weex开源

@dingyiming

期待WEEX开源

@smileEvday

Mark 一下,hybird开发又向前迈进了一步

@54lazycat

渲染时间300ms。这个真的不要紧吗?

@Jinjiang
Member
Jinjiang commented May 4, 2016

@54lazycat 会比纯 native 慢一些 (纯 native 一般会在 100ms 左右),但是带来的好处是很多的,比如灵活性和低发布约束等。当然这里在未来也许还有优化空间。

@theseawolves theseawolves referenced this issue in theseawolves/tasks Jul 13, 2016
Open

Weex学习 #4

0 of 3 tasks complete
@yolynn-bird

weex怎么实现Component暴露给js的呢,就像RN的通信机制依赖了宏RCT_EXPORT()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment