详解|天猫搜索前端技术历代记

导读:做者从 17 年双十一前开始接手天猫搜索前端,开发第一个需求—— H5 凑单页,到今天已经将近两年了。在这两年里,天猫搜索的前端体系发生了比较大的变化。今天分享一篇阶段性的总结文章,记录天猫搜索前端技术的过去、如今,以及本身做为业务目前的惟一前端对将来的思考。

大致划分css

首先基于前端技术的演进,大致上能够将天猫搜索前端的发展历程和将来趋势总结成几个时代:前端

  • PC 时代
  • H5 时代
  • MV* 时代
  • Weex 时代
  • 搭建时代
  • 深度搭建时代
  • 智能时代

之因此这么划分,主要是基于天猫搜索的前端技术方向以及天猫乃至淘系前端技术体系发生的较大变化。而在这其中能够再提炼时代的关键词:react

  • 封闭:PC 时代、H5 时代、MV* 时代
  • 开放:Weex 时代、搭建时代、深度搭建时代
  • 智能:智能时代

下面就来介绍各个时代天猫前端的技术状态和一些思考。webpack

一、PC时代

PC 时代能够说是天猫搜索前端的上古时代,那仍是手机流量很是贵的 3g/2g 时代。所以大多仍是简单的 WAP 页面,大多数人都仍是习惯用 PC 进行购物。ios

▐ 技术方案web

模块化后端

PC 时代的前端技术方案采用的是 KISSY + MUI 3 ,MUI 3 就是那套 KISSY 的模块规范 KMD 。页面上还有一些很是老旧的 YUI 依赖。在那个 jQuery 王霸天下的时代,基本上天猫的 PC 页面都是采用集团内部根据 YUI 自研的大而全的 KISSY 框架。KISSY框架包含了前端所须要的几乎全部基础功能:模块加载器、 DOM 操做、事件处理、异步请求等等。浏览器

页面渲染缓存

PC 天猫搜索采用了同步渲染的方式,页面的主要内容经过 VM 模板渲染输出到前端,所以前端须要维护大量的 Velocity 模板代码以保证 HTML 中的内容和本身 JS 代码可以配合得当。需求修改一旦涉及到 HTML ,就须要改造 Velocity 模板从而陷入 aone 发布的同步模板和部署炼狱之中。性能优化

模块管理

而 PC 时代的天猫搜索前端页面的模块管理方式十分粗暴,基于业务逻辑划分的大量 KISSY 模块,他们共同操做一个统一的页面 DOM ,交叉修改时有发生。模块间的通讯也是直接调用模块实例方法来实现,模块耦合很是严重。

▐ 小结

由此能够看到那个时代最主要的问题有以下几个:

  • 大而全的框架使得页面笨重、依赖繁杂
  • 前端花费大量成本去维护不熟悉的 Velocity 代码
  • 基于应用环境,常常性须要同步模板或部署,应用不稳定时甚至没法调试
  • 页面内模块化粗暴,模块耦合严重
  • 重 DOM 操做,DOM 管理混乱

二、H5 时代

随着智能手机的普及,4g 技术的发展使得流量费用的大幅降低,无线端需求不断增多,流量不断增大,天猫前端也将方向定为 mobile first 。显然 PC 搜索这一套技术方案没法知足 H5 搜索需求,所以 H5 搜索采用了全新的技术方案。

▐ 技术方案

模块化

H5 搜索采用 Zepto + MUI 4 做为模块化方案,MUI 4 相对 MUI 3 主要变化是将 KMD 规范修改为了业内较为通用的 AMD 规范。同时引入了前端模板来实现 DOM 的更新,首先 Zepto 要比大而全的 KISSY 轻量许多,同时前端模板的引入使得模块自我管理了 DOM ,有效的下降了模块之间 DOM 操做交叉引起的混乱。

页面渲染

H5 搜索的页面渲染基于应用控制,但仅仅将框架、筛选等一些少许 DOM 同步渲染,大多数 DOM 如商品列表都是采用异步渲染前端模板的方式实现。所以同步模板中的内容量相对较小,维护成本大幅度下降。同时引入了先后端分离的 wormhole app ,前端再也不须要维护不熟悉的 VM 模板,而是维护和异步模板语法相同的 xtpl 模板,进一步下降了模板维护的成本。

模块管理

与 PC 连翻页都是页面跳转的方式不一样,如筛选、翻页等行为的渲染须要前端异步处理,模块通讯的需求也相对复杂。H5 搜索采用了 MDV 框架——经过将模块封装成一个个模型,再由 MDV 创建的模型之间的订阅机制进行模块的实例管理,以此来实现模块通讯。

▐ 小结

H5 搜索采用的技术解决了几个 PC 搜索时代的问题:

  • 减少依赖,知足了H5的性能要求
  • 基于wormhole app的先后端分离开发,下降了模板维护成本
  • 引入前端模板,下降了DOM交叉管理的混乱
  • 引入MDV进一步使得模块解耦,规范了模块通讯

但随着业务的发展,依然发现有一些问题:

  • 虽然引入了前端模板,但全部更新和状态同步依然是手动的,依旧会频繁地 DOM 操做
  • 模块划分仍是基于逻辑划分,而非基于 DOM ,所以当一个逻辑模块须要操做多个 DOM 时,依然会引起交叉
  • 虽然模块对外是个黑盒,但模块内部状态常常由于交互逻辑和业务逻辑繁琐致使混乱,常常出现更新了状态没更新 DOM 的状况
  • 依赖应用环境,须要常常性同步模板和部署,毕竟 wormhole app 也是应用

三、MV*时代

在 all in 无线的大环境下,因为搜索结构较为固定、无线端开发资源较为充裕等等各类缘由,天猫搜索业务在端内彻底被 Native 承接,而 H5 更加注重端外和站外。这也致使了 H5 搜索的业务能力和 Native 脱节,仅保留核心筛选功能以及唤端功能。所以 H5 搜索很长一段时间几乎没有前端资源投入,而在 2017 年 8 月左右因为组织架构调整,我手上的天猫商品业务交接后,我开始逐步接手天猫搜索前端业务。而我要作的第一个需求,就是一个包含 H5 搜索 80% 功能的 H5 搜索凑单页。

▐ 技术方案

模块化

我和团队同窗采用 Preact + MUI 5 方案来实现,MUI 5 其实就是 MUI 4 的升级,采用 CommonJS 的写法来编写模块,再通过构建工具编译封装生成 AMD 模块。其实当时会场已经大规模采用 Vue Weex 了,那咱们为何要采用 Preact 呢,主要是基于以下几点考量:

  • 团队内对于 React 技术栈有至关程度的了解
  • Rax 的发展和普及以及 Weex 团队的一些调整,让咱们认为 Rax 是将来 Weex 的主要 DSL
  • Preact 相对于其余框架更加轻量,而搜索的页面虽然有必定交互,但比较简单,恰好能知足需求
  • H5 是将来大的趋势,当时兄弟团队在天猫超市的极致 H5 体验和沉淀给了咱们充足的信心

所以在这个阶段,咱们使用 Preact 作了不少的搜索周边的功能页面,如上面提到的 H5 凑单、还有猫搜的领券弹层、凑单领券页面、搜索分类页面等等。

页面渲染

因为 Preact 的异步渲染特性,页面渲染咱们直接抛弃了应用,而是采用斑马源码页面的方式。这样的好处是,前端再也不须要和 aone 频繁的打交道,服务端只须要封装一个 mtop 接口给前端,前端在斑立刻建立基础 HTML 引入资源并调用接口获取数据渲染便可,前端本身彻底掌控了调试、开发节奏。因为对于应用的依赖仅限于一个 mtop 接口,所以前端能够提早定好数据规范,在服务端开发接口的同时基于本地调试工具进行 mock ,大大下降了联调成本。

模块管理

React 生态有很是多的模块管理方案,咱们调研过的 Flux、Redux、Reflux 等等均可以知足咱们的需求。但通过仔细的思考咱们选择直接撸,不使用任何框架来管理模块通讯。如此考量的缘由主要遵循以下理念:

  • 首先咱们须要规划页面的模块结构和通讯结构
  • 若通讯结构与模块结构有较大的出入,且通讯结构并不是扁平,那么咱们就须要引入模块通讯框架来实现通讯结构的扁平化
  • 若通讯结构与模块结构出入不大,且通讯结构自己扁平,那么咱们就没有必要引入通讯框架
  • 保持模块结构清晰、分离,面向将来,若将来业务发展逐渐繁琐,能够再引入框架来处理模块通讯

▐ 小结

引入 MV* 框架后,咱们的技术方案又获得了一些提高:

  • 因为引入 MV* 框架,模块的划分再也不基于逻辑而是基于 DOM,DOM 的操做再也不须要手动处理, DOM 交叉操做被完全杜绝;
  • 使用斑马源码页面,再也不依赖应用环境,更方便的数据模拟和调试。再也不须要维护模板;
  • 模块内部状态基于 MV* 管理,状态再也不混乱,保证了 DOM 和模块状态的一致性;

这里仍是有一些问题:

  • H5 老是面对性能的挑战
  • 依然是源码开发,不够灵活,也没法共建
  • 每来一个需求,就须要页面总体修改和发布,有相似行业定制,只能从新开发一个

借鉴天猫超市极致 H5 经验,搜索在分类页作了很是多性能优化尝试,好比:

一、代码优化

  • 列表拆分 cell 进行懒加载
  • 接入 crossimage 优化图片加载的 cdn 后缀
  • 自建 solution ,去除通用 solution 中各类无用依赖
  • 升级最新的 loader 来提高计算性能

二、DNS优化

  • dns-prefetch,提早处理dns
  • 收敛图片和资源域名

三、接口优化

  • 使用dlp进行mtop接口缓存

四、埋点优化

  • 令箭埋点延迟到 pageload 后发布
  • 采用非覆盖式的 aplus 脚本,利用浏览器缓存
  • 采用 post 发送,触发 sendBeacon

五、加载优化

  • 增长 service worker 层缓存 js、css 和图片
  • 使用 zcache 缓存页面模板、 js 和 css

六、体感优化

  • 使用 ranger 自动添加 URL 隐藏导航栏参数,防止页面加载后手动隐藏出现的抖动

四、Weex 时代

17 年双十一以后,搜索一成不变的模式也受到挑战,在这个拥有大量流量和强用户心智的场景下,搜索可以玩出更多场景化、行业化、品牌化的玩法。所以产品上须要更多快速试错的机会,也致使对于动态化的诉求则日益增长。而因为一些组织架构调整,天猫搜索的客户端缩减到 2 人—— 1 个 ios 和 1 个安卓。客户端需求开发由于须要发版而迭代缓慢。所以催生了 Native 内嵌 Weex 坑位的技术方案和 Weex 模板下发的 Oreo 平台。

▐ 技术方案

模块化

其实在我进入到搜索以前,Weex 坑位方案和 Oreo 就已经在小范围使用了,有一部分客户端同窗写的 Weex 1.0 的 Vue 模块,另外还有一些 Weapp 模块。这些模块因为人员调整和离职已经很难找到仓库源码了。另外这些模块也是仅面向 Weex 的,对于 H5 来讲是彻底没法使用的。所以在我进入搜索以后,提出了Prax的解决方案,本质上就是使用 Rax 0.x(当时仍是0.4) + Preact 经过编译转换供Weex和 Web 同时使用。之因此要用Preact,主要是考虑到咱们有端外 H5 场景,可是 Rax 当时 H5 性能是真的堪忧,并且当时的Weex团队方向对H5性能优化投入并很少。另外从上面 MV* 时代能够看出咱们在 Preact + MUI5 的技术方案上也有较多的沉淀。最终咱们肯定了采用编写 Preact 代码,经过自动化工具转换成 Rax 代码的方式来实现一份源码同时复用在 Weex 和 Web 的技术方案。前端的开发流程就变成了以下:

  • 编写包含基础可复用纯 UI 代码的 Prax 模块
  • 对于 Native 内嵌 Weex 坑位,编写一个 Rax 模块, Rax 模块引用 Prax 模块的 Rax 部分,并增长诸如埋点、容器联动等功能,并经过专门的模板发布系统发布上线以供坑位使用
  • 对于 Prax 页面,编写一个斑马模块或页面,引用 Prax 模块。经过斑马平台发布上线,在端内使用 Prax 页面的 Weex 版本,在端外引用 Prax 页面的 H5 版本

页面渲染

Prax 页面采用斑马来处理页面渲染。因为源码页面都是采用打包的方式,所以脚手架中分别有 Web 和 Rax 两个打包 webpack 配置,构建时候分别运行生成 Weex Bundle 和 Web Bundle 。因为 Web 端本质上就是以前 Preact 的方式,所以渲染沿用了过去 Preact 的页面框架。而Rax则是开发了一个全新的页面框架。斑马渲染 Weex 页面本质上是经过xtpl控制 Weex Bundle 代码生成,因此源码页面编译出来的 Weex bundle 只须要在外经过 xtpl 增长一层 Weex 的头尾就能够了。

对于 Native 内嵌坑位,则是采用模板下发的方式。前端会编译生成一个自身可运行的 Weex Bundle ,包含头尾等完整信息,而后经过发布推送到搜索应用的机器上。当客户端的搜索请求到达服务端,服务端基于业务逻辑肯定须要使用哪些模块,将模块相关的信息告诉客户端,这些信息包括模块名称、模块位置、模块数据。客户端渲染 Native 页面时根据模块位置建立对应容器,并根据模板名称请求 Weex 代码,最后将代码渲染到 Weex 容器中,并传入模块数据,实现模块最终渲染。而在 Rax 代码中,咱们能够经过 window.__weex_data__ 拿到客户端塞给容器的数据。固然这些适配均可以在构建层面处理,通常状况下开发者只须要关注纯粹的 UI 模块编写便可。

模块管理

Prax 页面的模块管理和 Preact 开发时期基本同样。可是对于 Native 内嵌 Weex 坑位,模块管理方案就彻底不一样了。看起来 Native 内嵌 Weex 坑位只展现一个Weex模块,但其实是一个只有单一模块渲染的完整 Weex 页面。所以 Weex 模块之间是没法通讯的,它们甚至都不在一个 Weex 容器内。正由于如此 Native 内嵌 Weex 大多作一些纯展现的需求,对于复杂联动需求依然是交给客户端完成。另外客户端提供了一些通用能力,封装在 Weex 模块中,如:

  • 获取搜索当前筛选条件
  • 合并筛选条件并从新请求
  • 清空筛选条件并从新请求
  • Query 词替换
  • 一次筛选内 mtop 缓存机制
  • ...

▐ 小结

通过了 Weex 时代,咱们的技术又获得了提高:

  • 实现了一套代码同时复用在 Weex 和 H5
  • 经过引入 Rax ,咱们解决了端内的性能问题
  • 对于端外场景,咱们也保证了 H5 性能以及优化的抓手
  • 灵活的 Weex 发布机制突破了发版限制,知足了产品的动态化诉求
  • 对于搜索坑位,咱们也沉淀出了一套行业前端能够参与共建的机制

但这里仍是有几个问题没有解决:

  • 源码页面开发的问题依旧,不够灵活,也没法共建,也很差复制多个
  • 搜索坑位内模块展示逻辑是服务端硬代码控制,对于行业规模化和动态数据源接入都须要从新编码
  • 当多个模块同时做用于同一场景时,模块的展现逻辑就会交叉,引入各类各样的问题

五、搭建时代

至此咱们能够发现,如今搜索前端核心解决的问题逐渐变成了共建和规模化了,再也不是以前单纯前端技术问题了。既然要解决共建和规模化,咱们能够看看规模化成功的一个典型例子:会场。过去会场也是一个个页面前端人肉开发,到后来有了斑马就能够由运营模块化搭建了,前端只须要开发一些基础模块就能够知足全部行业的诉求,多么的美好!那么搜索是否是也能搭建呢?

答案是:“是的”,但毕竟场景不一样,咱们不能和会场同样楼层 duangduang 地堆砌,为何呢?

首先在场景的层面有比较大的不一样。在用户进入这个会场时,已经决定了当前的场景了,一个会场页面就是一个场景,所以在这个会场页面下,只须要圈出这个场景的模块就能够了。而对于搜索,全部的场景都须要在搜索这一个页面展现,而在搜索如何定义一个场景呢?

  • Query 词:用户搜了什么词,是品类词、仍是品牌词、仍是宽泛词、仍是一个具体的型号词
  • 类目:用户搜的词所属的类目是什么?哪一个一级类目?哪一个叶子类目?或者说是横跨不少类目?
  • 人群:用户本身是哪一个人群,潮流酷女?仍是居家好男人?
  • 时间:用户在什么时间来的?圣诞节?新年?生日?
  • LBS:用户在什么地方来的?附近是否是有提供服务的门店?
  • ...

这么多维度,一个或多个交织在一块儿才定义了一个场景,而在这个场景下会展现一个或多个模块。

以 Query 举例:

  • 用户搜索品牌词(如华为):展现品牌搭建的 Minisite
  • 用户搜索特定类目词(如香水):展现行业模块
  • 用户搜索礼物(宽泛词):展现礼物场景导购卡片
  • ....

固然,会场模块里面的货品彻底能够多样化,另外如今会场基于袋鼠也有千人千面模块的能力了,这里是拿以前的会场作例子

基于这样的思考,搜索启动了一个长颈鹿项目,以以前搜索域就有的一个产品——品牌 Minisite 做为切入点,为品牌商提供了一个全新的品牌运营阵地

如上图,从左往右分别是三个版本的 minisite 。这里能够看到, Minisite 做为品牌在搜索的一个搭建阵地,一直采用的是提供模块让品牌商填入数据的玩法。品牌商自定义程度很低、维护欲望很低,所以导购效率一直不高。而在长颈鹿项目中,搜索在商品列表层之下又新开了一个层,在这个层里展现一个品牌商家搭建的页面,在这个页面中品牌商家能够充分的自定义。而对于一个跨品类经营的大品牌,咱们也开放了品牌词+主营类目词的组合,方便其对每一个主营类目去搭建本身的页面。

而在品牌词下取得成功后,咱们将能力扩展到了行业侧,在搜索中台——美高上建设了心智造产品。让行业也能够基于一样的方式去经营品类词,搭建行业本身的页面。

心智造和 Minisite 分别是针对品类词和品牌词,相互不会交叉。而对于一些横跨多品类的平台级需求,好比一些频道相关的需求和拉新相关的需求,是很是容易与其余场景交叉的。为了解决这个问题,咱们在美高上沉淀了一套模块定投方案——无界,经过模块级别的投放,让场景之间的交叉变成可能,只须要简单定义模块展现的规则,就能让不一样场景的模块展现在同一个页面上。

▐ 技术方案

模块化

首先是心智造和 Minisite ,它们的核心技术方案是类似的——都是采用千叶(一个给商家用的页面搭建平台)做为模块搭建平台,并在千叶的搭建能力之上,包装了一层页面投放策略的管理。其实到这里,模块化方案和会场并没有二致,只是模块的实现采用了 Prax 来兼容 Weex 和 H5 :

一、编码阶段

  • 每一个模块都会定义本身投放的数据结构
  • 模块内不包含页面通用依赖(如 Rax 基础组件、 mtop 等)

二、渲染阶段

  • 有一个 Solution 控制页面模板的渲染,对于Weex则是负责包裹 Weex 头尾
  • Solution 将模块相关数据规整,Web模块代码能够异步获取, Weex 通常同步输出到 Bundle 中,而模块所用的数据都会放在页面上提供一个简易方法获取
  • Soluiton 引入 PI(页面初始化脚本), PI 将相关模块数据取出根据模块信息获取模块代码进行渲染,并从页面上获取数据交给模块

而到了无界,这些就彻底不 work 了。毕竟无界是走的模块级定投,容器只有一个,所以投放场景极可能和心智造、 Minisite 场景交叉:

  • 没有模块也没有心智造和 Minisite 页面,那么咱们就须要建立一个只展现无界模块的页面
  • 已经有心智造或 Minisite 页面了,咱们须要将当前模块插入到页面中

而咱们采用了以下技术方案将无界的定投模块插入到页面中:

  • 用户发起搜索,搜索请求到达服务端
  • 服务端请求返回时,若命中心智造和 minisite 场景,则返回对应场景投放的千叶页面 URL
  • 服务端请求返回时,若未命中心智造和 minisite 场景,且命中有无界定投的模块,则返回一个空页面 URL
  • 服务端请求返回时,若命中有无界定投的模块,则返回无界定投模块信息,包括模块名称、模块版本、模块数据、展现规则
  • 客户端建立长颈鹿 Weex 容器,渲染心智造、 minisite 页面,或者空页面,而后将无界定投模块数据传入 Weex 容器
  • 页面渲染触发 PI 执行,PI 获取无界定投模块,拉取定投模块的代码,建立实例后基于展现规则插入到页面中

经过这样的方式,最终渲染出当前场景下全部的模块内容。另外在无界后台咱们有一套场景干预规则,解决场景交叉时进行一些手动干预。与此同时咱们还提供了一套动态数据源机制,方便三方 HSF、TPP 数据能直接绑定到模块上,实现模块和数据解耦。

页面渲染

页面渲染如上述所示,依旧是经过斑马。但与以前不一样的是:

因为是模块化搭建,页面经过 PI 统一管控,页面渲染依赖 PI 行为控制

对于长颈鹿容器,一样是 Native 建立 Weex 容器渲染,但与以前渲染一个仅包含一个模块的 Weex 页面显然是不一样的,长颈鹿容器内渲染的也是一个真正的模块化搭建的页面

对于无界定投的模块,提供了插入机制,解决了场景交叉时的展现问题

模块管理

对于页面内的通讯,因为页面经过 PI 统一管理,也就意味着模块的各类能力都须要依赖 PI 来进行实现。因为这样的楼层搭建通常通讯结构都是扁平的,因此基本上经过模块冒泡给 PI , PI 下发给对应模块便可。不过通常不建议模块之间进行通讯。

对于页面和容器通讯,咱们是在 PI 中提供了一些封装的能力,另外也能够本身调用容器提供的方法,与 Native 内嵌坑位的 weex-module 方案别无二致。

▐ 小结

因为长颈鹿内的技术方案已经脱离传统意义上的前端,更多设计客户端和服务端,是整个产品架构的设计,这里很难讲清楚,放一张图可能清晰一点:

这里前端技术又有了提高:

  • 实现了可视化搭建,为商家&行业提供了运营阵地
  • 为将来品牌&行业规模化提供了基础
  • 提供了更好的行业共建机制
  • 动态数据源+无界模块定投能力更加灵活多变

但这里咱们仍是有几个问题还没有解决:

  • 咱们和会场愈来愈像了,可是咱们和会场模块并不互通(会场终于也用 Rax 了,可是他们用的是 Rax 1.0,咱们仍是 Rax 0.6)
  • 搭建的粒度太粗,基于楼层的搭建不够灵活没法知足行业差别化诉求(想象一下搜索列表做为一个模块时,只是商品样式改下就要从新开发一个搜索列表)

六、深度搭建时代

搜索最擅长的显然就是搜索结果页那种商品瀑布流,将用户最想要、最有可能购买的商品推荐给他们。而这个能力也能够复用在诸如首页、频道、店铺、专辑等等地方。而当咱们要在不少不一样的地方去搭建这样一个列表页时,在上面所说的楼层搭建中,咱们通常会怎么作呢?

  • 首先,新建一个 XXX 搜索列表模块
  • 找一个无尽列表组件
  • 开发这个业务须要展现的商品坑位
  • 将无尽列表组件里的 loadmore 中去请求 mtop 获取下一页数据
  • 将模块发布供搭建使用
  • 当有新的需求,就新增一个标记来判断,基于标记换一个数据和商品坑位展现

若是这么处理,若行业大面积规模化,会出现以下几个问题:

  • 不一样行业对于商品展现的要求不尽相同, 好比家电行业都会展现一些比较关键的产品属性,而家装行业则要更突出一些上门安装的服务,这也就致使商品坑位的展现不一样,同时也意味着大量的开发成本
  • 因为在一个仓库内开发,共建会更加困难,全部需求都会更容易压到本身头上
  • 因为对接不一样数据源,当业务逻辑出现交叉,前端代码里的各类判断也会指数级增长

这些显然都是咱们不肯意看到的,咱们将组件的不一样场景彻底剥离,能够发现一些规律:

  • 无尽列表既然能抽出一个组件,那么它确定是能够复用的
  • 商品的展现和数据源的接入其实很是适合共建,让行业的前端对接行业本身的数据=专业的人作专业的事

进一步提炼:

  • 交互可复用
  • UI 根据场景自定义
  • 数据根据场景自定义

因此咱们有没有可能在这个理念上更深一步进行搭建呢?

模块化

答案显然是有的,深度搭建的概念其实就是用来解决这种问题。将页面上的模块基于功能进行了从新定义:

  • 数据模块:自身没有任何 DOM 相关代码,只负责处理数据。而且监听一些事件,这些事件触发时会加载新的数据并将其交给接收其数据的下游模块,触发刷新
  • 容器模块:自身实际上是一个容器,负责接收数据,并将数据下发给展现模块去展现。但它自身不处理数据,而是经过触发数据模块定义的事件接口,告诉数据模块须要作什么。
  • 展现模块:UI 展现模块不处理任何逻辑,惟一作的就是拿到交互容器模块给他的数据作展现。它内部甚至不处理任何事件,全都是以冒泡的方式到交互容器模块进行处理。

经过这样子的划分,容器模块控制了交互、展现模块控制了 UI 、数据模块控制了业务逻辑,好比一个包含筛选、商品流的列表更具体用 React hooks 来讲就是:

  • 数据模块本质上就是一个 reducer,对外暴露一个 [state, dispatch], state 包含筛选信息、商品数据,交给容器模块渲染;而 dispatch 则定义了 loadmore 、 changenav 等方法,供容器模块调用
  • 容器模块将导航和商品坑位定义为纯展现区域,将筛选信息、商品数据传给关联的展现模块进行渲染,并传递给他们一些如点击事件的回调方法,当筛选发生点击时经过 dispatch 触发数据模块的 changenav ,而页面下拉到底时经过 dispatch 触发数据模块的 loadmore
  • 展现模块就是纯粹的无状态 UI 组件,不一样的组件用来展现不一样的区域

合理的场景划分相当重要,不一样业务场景应该是数据模块+容器模块+展现模块的组合,大多数状况下容器模块和展现模块能够复用,但数据模块都是须要从新开发的。尽量让数据模块来适配容器模块和展现模块,不改变交互就不改变容器模块,不改变UI就不改变展现模块。

在这里模块的编写切换到了 Rax 1.0,与会场的开发方式一致以实现复用。Rax 1.0 针对 Web 作了不少优化,打出来的 bundle 也更加轻量,性能也好了不少,已成为天猫前端业务开发主要方式,所以再也不须要使用 Prax 了。

页面渲染

这里和传统搭建有个很重要的不一样,模块之间出现了关联关系。好比以下关联:

  • 数据模块须要和容器模块&展现模块相关联,须要将 state 和 dispatch 交给对应模块
  • 展现模块与容器模块管理,容器模块定义了区域,不一样区域使用不一样的展现模块
  • 容器模块甚至能和容器模块作关联,实现多层嵌套展现,这种状况通常用于纯展现,不涉及交互(好比搜索列表筛选栏和商品瀑布流中间的空白区域)

那么咱们就须要一个全局方式来处理这些关联。首先须要在搭建模块的时候去指明模块之间的关联关系,好比我本身是定义了三个字端:

  • key :模块的惟一标识,给容器和数据模块使用
  • data :若是是容器或展现模块,在其中填入所使用数据模块的 key
  • container :若是模块在另一个容器以内,则在其中填入所在容器模块的 key

data 和 container 都是二段结构的,好比 data 的 a:b 表明使用 key 为 a 的数据模块的 b 字端内的数据,而 container 的 a:b 则表明使用key为a的容器模块,并将本身做为其 b 区域的展现模块使用。

这几个字端都会在脚手架里,初始化时生成到 schema.$attr 中。而真正负责识别这些字端并将模块串起来的天然是页面初始化脚本—— PI ,PI 干了以下事情:

  • 扫描全部数据模块,并将其实例化,存放在一块儿,并从渲染模块中将其剔除
  • 将剩余的渲染模块基于 container 组织成一个树形结构,并对每一个节点基于 data 关联数据模块,并将最上层进行渲染
  • 将子模块相关数据传递给容器模块,并提供一个默认渲染方法。容器模块能够本身决定如何处理这些子模块相关数据,能够修改、合并、覆盖,修改完后使用渲染方法渲染便可。若其中还有还有下一级子模块,重复进行以下操做

模块管理

这里模块的通讯有两种,一种是基于公用数据模块的通讯,一种是基于 PI 的通讯。

一个页面上能够有多个数据模块,而每一个数据模块均可以对接到多个容器/展现模块(这也是为何 data 是二段结构的缘由)。所以当多个模块须要通讯的时候,能够经过dispatch触发数据模块行为,数据模块刷新数据影响另一个模块。

基于PI的通讯通常都是针对一些特殊场景,好比一个很经典的例子——筛选列表筛选栏变形吸顶:当页面有不少模块,筛选列表并非全屏大小而是跟着整个页面一块儿滚动,当筛选栏滚出视野外,它须要变成一个相对简单的结构吸顶。在这种场景下,因为吸顶层自己是一个绝对定位的层,而页面文档流也是一个层,两个层之间不基于 DOM 操做的话,最合理的方式就是基于一个数据模块进行状态共享。如吸顶组件定义了吸顶时的样式和正常的样式,而且暴露一个建立数据模块的方法, PI 在渲染吸顶组件时会单独为其建立一个数据模块来共享筛选栏状态。

▐ 小结

为何要搞的这么复杂?其实就是但愿能将 UI 和交互作的更加纯粹,当 UI 和交互都是针对单一场景、足够简单的时候,咱们就能引入一些产品来进行提效,好比:

  • 使用描述式的方式来零开发定义交互,生成容器模块,如 domagic
  • 使用描述式的方式来零开发定义 UI ,生成展现模块,如 imgcook /魔切

经过这这样的方式,最终页面上大多数内容都变得能够复用,规模化的成本也就大大下降了。

七、智能时代

因为搜索还在深度搭建时代探索,如下是我基于团队方向 YY 的,但我相信这个时代很快就会到来

但上述的各类方式终究仍是人肉的,须要人力投入的。既然工具能让咱们以配置的方式解决交互和 UI ,那么有没有可能连配置都不须要,机器自动帮咱们生成一个数据模块或者交互呢?

这就是咱们团队正在作的,目前团队的同窗正在尝试基于机器学习训练模型实现智能化UI。只须要给出一些关键信息(好比要展现商品的哪些字端),就会自动化的生成对应的展现模块或交互模块。这些模块使用到深度搭建之中,前端就只须要经过数据模块定义展现的内容来源就能完成整个页面的搭建。实现UI零成本。

而咱们进一步扩展去思考,把大象装冰箱分为三步,那么把搜索智能化应该也只须要三步:

  • 第一步,咱们告诉机器要展现什么内容,它用最高效的方式展现给用户
  • 第二部,咱们告诉机器要展现哪一类的内容,它找出这一类内容最高效的方式展现给用户
  • 第三部,咱们告诉机器咱们的场景,它找出符合该场景的内容展示给用户

具体一点多是:

  • 第一步,咱们有了商品,让模型去训练出最好的商品展现方式
  • 第二步,咱们定义了说这里要展现一个权益模块,那么模型会给出最合适的展现内容,好比说展现一张店铺券,是展现店铺券的同时展现几个爆款商品诱导用户去下单,仍是站在一个商品的维度将店铺券结合品类券、津贴一块儿给出一个惊人的折扣价诱导用户下单,抑或是找出当前用户指望购买的商品总价最接近的店铺券展现并诱导其凑单等等
  • 第三步,咱们定义了一个场景,好比告诉机器这是一个 XX 频道,那么机器自动能分析母婴频道的主力消费人群类型,而后针对这我的群类型去推荐最合适的内容。好比假设咱们要搭建一个母婴频道,机器会自动基于母婴频道主力消费人群是宝妈,而宝妈养娃最痛苦的是需求商品种类繁多、同时质量担忧得不到保证,所以给她推荐内容导购为主,同时穿插着一些品质上的背书好比用户评价、品牌保证、平台服务等等。

所以,咱们可能须要一个三层的模型:

一、第一层基于不一样的内容,找出最合理的UI界面来进行展现,也就是智能UI模型。

二、第二层则是须要产出这些内容,这里分了三个维度:行业&平台+品牌&店铺+货品。

  • 针对行业差别化的诉求,行业运营决定这里须要展现的行业内容的类型和形式,好比刚才说的权益带商品的模式,那么就要经过行业表达模型找到最合适的权益以及结合这个权益之下最合适的货品;
  • 针对纯粹的商品展现,则是将人货场的匹配作到极致,找到这个用户目前最想要的商品;
  • 针对品牌&店铺,品牌须要塑造品牌在消费者侧的心智,对应的品牌会有本身的表达,好比品牌想要将一个新品打形成爆款,那么对于这个爆款的打造就须要一个品牌表达模型来辅助他们运营;

三、第三层则更为复杂

  • 行业内容模型其实就是行业运营经验的沉淀,将运营目标具像成不一样的场景,再将该场景下的运营经验具像化成内容,这里就须要行业侧各类类型的内容做为输入,而模型则须要基于以往的各类组合后的运营经验,给出最合适当前场景的内容组合;
  • 品牌内容模型也是相似的,整合吸取品牌在整个淘系体系下的各类资源投放,为品牌&店铺的运营提供一些行之有效的运营建议(推荐模块),提高品牌运营的效率,下降运营成本;
  • 对于人货匹配则是再拆分了三个模型,分别去处理货品、场景和用户;

货品模型:从货品中提炼出货品中的最吸引人的一些特质,好比卖点、好评、销量,以及将货品结构化,方便货品在不一样的地方展现;

场景模型:基于用户的实时行为来定义当前用户的购买场景,他可能想买一台电视因此浏览了不少电视,抑或是在一家卖电视的专卖店里面找同型号线上价格,抑或是在过年准备给父母购置一台电视做为年货等等;

用户模型:基于用户的历史行为,将用户划归某个类型的人群,进行人群精细化运营。好比一个用户常常购买年轻人的潮流酷玩,但每到父亲母亲节或者特定时间就会购买一些长辈礼物的品类,说明是个有孝心的boy/girl,那么针对这类孝顺宝宝就能够在不一样的节日或其余重要日子推荐一些给长辈送礼的内容

那么咱们都有哪些数据呢?

  • 行业&平台:行业有本身的沉淀,平台有各类营销玩法
  • 品牌&店铺:品牌一样有主打新品、限时优惠、专题活动、线下门店等等
  • 货品:各类商品沉淀下来的属性、评价、卖点等等
  • 用户离线:用户的各类行为历史,以及手动收集的一些用户档案
  • 用户实时:好比它最近的一些行为,从哪进入页面,在什么地理位置,什么时间点

One More Thing

因为咱们不是活在将来,所以没法判定前端的将来究竟是怎样的,但前端不会中止对于将来的探索。而这个将来不仅是技术的将来,也是业务的将来。技术和业务是咱们前进的两条腿,业务的诉求推进技术迈向新的高度,而更先进的技术也为业务带来更多的想象空间。

若是你不想再沉溺于过去,不想再埋头作为业务切页面的工具人,那就加入频道与 D2C 智能团队吧。有意向者请发送简历到 :tianxiang.wly@alibaba-inc.com



本文做者:王令宇(天镶) 

阅读原文

本文为云栖社区原创内容,未经容许不得转载。

相关文章
相关标签/搜索