如何设计实现 H5 页面搭建系统 - 数据模型
如果无法正常显示,请先停止浏览器的去广告插件。
1. 如何设计实现 H5 ⻚页⾯面搭建
数据模型
京东京喜前端团队 沐童
2. CATALOG
⽬目录
01 MPM 整体介绍
02 数据层⾯面临的痛点
03 ⻚页⾯面模型设计
04 请求模型设计
05 总结
3. 01
MPM 整体介绍
4. 上线服务4年年+,系统迭代超3个版本
Mart Page Maker
累计使⽤用⼈人数1400+,搭建⻚页⾯面1.9w张
除⽇日常活动外,承担80+%的⼤大促会场
H5 卖场可视化搭建系统
5. MPM能⼒力力概览
搭建物料料丰富
MPM 现有 30+ 个组件、500+ 个模板,业务能⼒力力覆盖商品、导
购、营销等多个场景。
配置功能强⼤大
三端渲染是 MPM 的强⼤大能⼒力力,除此之外,MPM 还⽀支持⻚页⾯面配
置 BI 排序、⾃自动化埋点、⾃自动化测试、⻚页⾯面测速等。
系统能⼒力力全⾯面
MPM 为⻚页⾯面保驾护航,不不但配备了了流畅的拖拽编辑器器、实时预
览和⻚页⾯面健康诊断能⼒力力,还对系统和⻚页⾯面做了了全⽅方⾯面的监控和容
灾降级⽅方案。
6. MPM效果展示
2、选择你需要的
模板
1、从这⾥里里拖⼀一个
组件到预览区
7. MPM效果展示
4、发布⻚页⾯面
3、配置楼层组件
属性
8. MPM效果展示
9. MPM系统架构
10. MPM⼯工作流程
11. 02
数据层⾯面临的痛点
12. 解决场景
“
请求散乱⽆无章
⻚页⾯面请求茫茫多,有时候想定
位⻚页⾯面中某个请求来⾃自哪个组
件,可能得定位半天……
卖场承载各线业务,接⼝口场景繁杂,如果简
”
单地将请求交给组件⾃自身各⾃自发起和处理理,
维护起来⼗十分麻烦。
13. 解决场景
“
多余的重复请求
某个⻚页⾯面,多个组件都配置了了
同⼀一个预约 ID,导致⻚页⾯面发出
了了 N 个⼀一模⼀一样的预约状态查
询请求……
缺乏数据请求统⼀一管理理的后果就是,这些⽆无
”
效的重复请求将严重拖垮你的⻚页⾯面性能。
14. 解决场景
“
接⼝口压⼒力力⼤大
商品接⼝口⽀支持批量量请求,可我
们⻚页⾯面中多个商品组件的接⼝口
请求并没有合理理聚合,⾛走批量量
调⽤用……
同个⻚页⾯面经常会多次请求同个业务接⼝口,这
”
对接⼝口服务造成了了⼗十分⼤大的压⼒力力。
15. 解决场景
“
数据模型多变
商品组件下的各个模板,除请
求商品之外,有些模板会拉取
新⼈人价,有些模板会拉取补贴
价……
组件对应多个模板,每个模板都可能对应了了
”
不不同的数据模型。
16. 解决场景
“
三端同构诉求
以 Vue 为例例,我们习惯在组件
created 时请求数据,这在客
户端渲染时⼗十分完美,但在直 Vue ⽀支持 SSR,但却⽋欠缺对异步数据获取的
出场景却完全⾏行行不不通…… 同构⽀支持,为了了适配 MPM 的三端同构,数
”
据层设计必须考虑这个问题。
17. 定义
为⾃自搭建卖场打造的⼀一套⾼高效通⽤用的数据请求解决⽅方案
1
2
3
统⼀一管理理 ⾃自由组合 适配三端
维护请求秩序,优化
请求性能 数据模型即插即⽤用,
⾃自由组合 为三端同构提供统⼀一
的数据请求⽅方案
18. 03
⻚页⾯面模型设计
19. PageData
PageData 是⻚页⾯面的抽象描述层
解析引擎
PageData ——————> 真实⻚页⾯面
interface iPageData {
pageId: number;
⻚页⾯面级配置
1)⼀一些基础配置,⻚页⾯面级别的请求,如楼层 BI 排
序查询在这⾥里里发起。
2)⻚页⾯面对⽤用户身份的要求配置,⽤用户级请求,如
⽤用户身份查询在这⾥里里发起。
组件级配置
包含了了组件楼层的配置,因此这份配置决定了了组件
楼层的业务数据获取。
// ⻚页⾯面id
⻚页⾯面配置
基础信息配置
搜索配置
分享配置
pageConfig: {
basic: iBasic;
search: iSearch;
share: iShare;
}; //
//
//
//
userConfig: {
checkNewUser: boolean;
}, // ⽤用户配置
// 1)是否需要查询新⼈人
componentConfig: iComData[] // 组件配置
}
20. ComData
ComData 是 PageData 的核⼼心部分
模板配置
指定使⽤用某个模板,引擎将根据这个配置使⽤用相应
的组件模板进⾏行行渲染。
数据配置
楼层配置数据,这⾥里里包含了了组件请求接⼝口所需的参
数。
组件关系
描述了了组件的⽗父⼦子级对应关系。
interface iComData {
uid: number;
source: string;
data: object;
styleKey: string;
parentUid: number;
children: iComData[];
}
//
//
//
//
//
//
组件id
数据源标识
组件配置数据
组件模板id
⽗父组件id
⼦子组件
21. 04
请求模型设计
22. 数据源及请求优化策略略
- 统⼀一管理理 + ⾃自由组合 -
23. 数据源
数据源是请求模型的基本单位,描述了了⼀一类请求动作
接⼝口地址
1
每个数据源对应了了⼀一个接⼝口
请求后置处理理
请求响应后的⼀一些通⽤用的数
据处理理逻辑
聚合分发策略略
描述了了如何对多个同接⼝口请
求作请求聚合和响应分发
请求前置处理理
2
3
发起请求前的参数组装处理理
4
5
6
⼊入参校验
对⼊入参进⾏行行校验,不不合法⼊入
参将不不会发起请求
监控统计配置
接⼝口监控、统计相关的配置
24. 数据源
// 数据源模型
数据源是⼀一个 class,以配置数据
为参,实例例化后可以得到⼀一个请求
对象。
每个数据源都有⾃自⼰己的名称标识,
调⽤用层通过指定数据源标识,来选
择调⽤用某个数据源。
interface iDataSource {
url: string;
// 请求地址
params: object;
// 请求参数
verify (params: object): boolean;
// 参数验证
beforeRequest (config: MPMComConfig): any; // 请求前置处理理
afterResponse (result: any): any;
// 请求后置处理理
batch: iBatch;
// 聚合分发策略略
monitor: iMonitor;
// 监控统计配置
}
// 组件/模板直接调⽤用数据源获取「商品」
dataServive.fetch({ source: 'skus', ...data })
25. ⾃自由组合
1
数据源理理应纯粹⽽而专⼀一
数据源应该只做⼀一件简单的事,⽐比如请求响应的⼀一些通
⽤用处理理,特殊业务逻辑不不应该在数据源中出现。
2
⾼高级请求模型由数据源组合⽽而成
复杂的请求模型可以由多个数据源组合⽽而成,调⽤用层可
以直接调⽤用数据源,也调⽤用封装好的⾼高级请求模型。
26. ⾃自由组合
// 商品 + 优惠券
请求模型的组合采⽤用最简单灵活的
函数调⽤用,这种组织⽅方式对多变的
请求模型⼗十分有利利。
向上,我们将调⽤用⽅方式对⻬齐,对开
发者来说,调⽤用单⼀一数据源还是⾼高
级请求模型,没什什么区别。
async skuWithCoupon (data) {
// ...
const skus = await dataServive.fetch({ source: ‘skus' });
const coupons = await dataServive.fetch({ source: ‘coupon' });
// ...
return result;
}
// 组件/模板间接调⽤用数据源获取「商品+优惠券」
dataServive.fetch({ source: 'skuWithCoupon', ...data });
27. 统⼀一管理理
28. 请求优化策略略
避免重复请求
依靠⼀一个简单的请求队列列
和请求缓存,我们有效避免了了
⻚页⾯面内发起重复请求
29. 请求优化策略略
请求的聚合分发策略略
interface iBatch {
limit: number
pack: (actions: Action[]) => Action
unpack: (result: any, actions: Action[]) => Record<ActionMd5, ActionData>
}
数据源可制定聚合分发策略略,使得
1
同类请求对象在发出前经 pack 合
并,响应后经 unpack 拆包分发
引擎以队列列收集请求对象,会等到下
2
⼀一个 Tick 再发起请求,在这个 Tick
中,如果队列列超限,就会提前发起
30. 请求优化策略略
合并同类请求
每个数据源可定制⾃自⼰己的
聚合分发策略略,以此让同类
请求合多为⼀一
31. 初态函数
- 三端同构 -
32. 假如不不考虑同构
灵魂拷问:前后端渲染有什什么区别?
我想把客户端渲染那⼀一套,照搬到直出端,为什什么不不⾏行行?
33. 假如不不考虑同构
客户端的渲染流程
客户端允许存在多趟渲染,中间以⻣骨架屏占位,渲染与请求没有严格的先后顺序
34. 假如不不考虑同构
直出端的渲染流程
直出端只有⼀一趟渲染,渲染前要求数据全部到位,所以请求必须在渲染之前完成
35. 假如不不考虑同构
结果你直出了了⼀一份⻣骨架屏?
如果你把客户端渲染直接搬到直出端,很遗憾,你可能就只能直出⼀一份⻣骨架屏
36. 基于三端同构的请求模型
1
同构的关键在于初态渲染
前后端同构的关键就是初态渲染,也就是⻚页⾯面的初始化渲染阶段。
2
补充适配直出端的⽣生命周期
Vue 现有⽣生命周期没有任何⼀一个能够满⾜足直出端的异步数据获取,
要实现直出,数据模型就必须补充适配直出渲染的⽣生命周期。
3
三端解析流程应保持统⼀一
要实现三端同构,我们还需要规范解析流程,让三端解析渲染流
程保持⾼高度统⼀一。
37. 初态函数
位于组件⽣生命周期之前的异步函数
interface iMPMComponent {
// ...
getInitialState (config: MPMComConfig): Promise<MPMComData>;
// ...
}
1
每个 MPM 组件都有⼀一个初态函数, 三端引擎在创建组件实例例前,将先收
初态函数以组件配置数据为⼊入参,异 集执⾏行行各组件的初态函数,并将函数
步返回⽤用于组件初始化渲染的初态数
据。
2
的异步返回结果作为组件初始化渲染
的数据。
38. 基于三端同构的解析流
静态 H5 / ⼩小程序端
39. 基于三端同构的解析流
直出端
40. 初态请求优化
刁钻场景:主次接⼝口分端渲染
我有⼀一个组件,串串联请求了了主、次两个接⼝口,可是次接⼝口内容没那么重要,为了了提⾼高直出效率,
能不不能只直出主接⼝口,次接⼝口等到了了客户端再请求呢?
41. 初态请求优化
主次接⼝口数据的分端请求渲染
主次接⼝口串串联时,主接⼝口在直出端完成,次接⼝口在客户端补充,提⾼高直出速度
interface iMPMComponent {
// ...
getInitialState (config: MPMComConfig, callback: (data: MPMComData) => boolean): void;
// ...
}
1
初态函数的第⼆二个参数是⼀一个回调 对于这类初态函数,直出端只会响应
函数,传⼊入初态数据并执⾏行行可以触 第⼀一个 callback,余下的 callback 将
发引擎⽴立刻渲染,因此,利利⽤用它可
以实现初态数据的分段渲染。
2
直接忽略略,等到了了客户端之后再作执
⾏行行,补充初态数据。
42. 05
总结
43. 01 相⽐比独⽴立开发⼀一个⻚页⾯面,搭建场景开发可能随处都要求着严
02 数据模型解决⽅方案更更多只是⼀一套开发范式,没有规范约束的
03 独⽴立和统⼀一并不不⽭矛盾,虽然搭建的⽬目的是⾃自由组合,但在设
谨的设计,任何你认为的微不不⾜足道都不不应该被忽视
搭建系统是不不可维护的
计开发时却必须⾜足够重视统⼀一的思想
44. THANKS
感谢您的观看
欢迎关注我们
45.