客服订单详情页体验升级之路
<h1 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">1、</span>背景</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">做为</span>客服域<span style="color: black;">拜访</span>量最大的页面之一,订单详情页在客服的<span style="color: black;">平常</span>工作中被用来查阅用户的订单信息,以此为进线的买卖家用户<span style="color: black;">供给</span>更好的购买服务,<span style="color: black;">从而</span><span style="color: black;">提高</span>用户的满意度。无论是一二线客服还是客服管理者,都能在<span style="color: black;">平常</span><span style="color: black;">运用</span>的系统中直接<span style="color: black;">拜访</span>到详情页,</span><strong style="color: blue;"><span style="color: black;"><span style="color: black;">因此呢</span>客服订单详情页的入口<span style="color: black;">亦</span>比较多,<span style="color: black;">日前</span><span style="color: black;">已然</span>超过了10处</span></strong><span style="color: black;">。</span></p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/af84fa87c6cc462d9e42878f8a286d5c~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=Lm27JT1kCsk6AP%2B%2FAwU02xIwKwg%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">随着得物业务的快速发展,客服订单详情页<span style="color: black;">必须</span>展示的信息越来越多,<span style="color: black;">必须</span>支持的操作<span style="color: black;">亦</span>越来越多,在页面改版前,一个页面首屏就<span style="color: black;">必须</span>展示80条订单信息,<span style="color: black;">详细</span>数量会<span style="color: black;">按照</span>订单类型、交易状态、物流状态等<span style="color: black;">原因</span>而改变。</span><strong style="color: blue;"><span style="color: black;">一个页面最多<span style="color: black;">状况</span>会有200条信息、60个按钮以及20个订单标签(不含用户标签、商品标签)</span></strong>,<span style="color: black;">因此</span>会<span style="color: black;">显现</span>一个现象,一个1920*1080分辨率的<span style="color: black;">表示</span>器(客服常用的分辨率),鼠标滚轮<span style="color: black;">必须</span>滚2次<span style="color: black;">才可</span>从页面的最上方滑到最下方,详情页信息截图如下所示。</p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/1823bfd72ac1440992676b6ed5d512d8~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=HyAVtoSgIborerbDkMNLFY1y3zo%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">另一方面,贸然<span style="color: black;">调节</span>反而会降低客服<span style="color: black;">朋友</span>的工作效率。页面内容、交互变化太大对客服<span style="color: black;">朋友</span><span style="color: black;">亦</span>存有不小的培训成本,</span><strong style="color: blue;"><span style="color: black;"><span style="color: black;">因此呢</span>秉持着变更影响最小化的原则,信息量<span style="color: black;">始终</span>保持着只增不减</span></strong>。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">经过一段时间的沉淀与打磨,客服订单详情页无论是客服的<span style="color: black;">运用</span>体验,还是<span style="color: black;">研发</span>体验都得到了<span style="color: black;">明显</span><span style="color: black;">提高</span>,</span><strong style="color: blue;"><span style="color: black;">订单<span style="color: black;">关联</span>的TS问题近半年<span style="color: black;">始终</span>保持清零状态</span></strong>。这<span style="color: black;">时期</span>做了<span style="color: black;">非常多</span>尝试和渐进式优化,本文<span style="color: black;">重点</span>从以下三点<span style="color: black;">详细</span>聊聊对客服订单详情页体验升级做的<span style="color: black;">有些</span>思考和优化。</p><span style="color: black;">这么信息全的页面,几乎所有客服域平台都要能直接<span style="color: black;">拜访</span>查阅,</span><strong style="color: blue;"><span style="color: black;">一个页面<span style="color: black;">怎样</span>多个系统<span style="color: black;">运用</span>,在<span style="color: black;">保证</span>客服<span style="color: black;">朋友</span><span style="color: black;">运用</span>体验的<span style="color: black;">同期</span>,还能节省<span style="color: black;">研发</span><span style="color: black;">朋友</span><span style="color: black;">守护</span>成本</span>。</strong><span style="color: black;">信息量大数据源多<span style="color: black;">引起</span>页面加载慢,客服<span style="color: black;">朋友</span>经常反馈卡顿,</span><strong style="color: blue;"><span style="color: black;"><span style="color: black;">怎样</span>对页面首屏进行秒开优化,进一步<span style="color: black;">提高</span>客服<span style="color: black;">朋友</span>的<span style="color: black;">运用</span>体验</span></strong>。<span style="color: black;">简单的改动<span style="color: black;">亦</span><span style="color: black;">必须</span>投入资源,信息模块复用率低,</span><strong style="color: blue;"><span style="color: black;"><span style="color: black;">怎样</span>建设信息自由编排、信息模块拔插的能力,最大程度解放产研运<span style="color: black;">朋友</span>生产力</span></strong>。<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"></span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">2、</span>多入口的页面复用</h1>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">1、多实例iframe</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">最早订单详情页只是客服工单系统中的一个页面,<span style="color: black;">运用</span>的是Vue2、ElementUI的技术栈。客服工单系统的定位是后台管理系统,<span style="color: black;">运用</span>门槛较高,更适合管理者<span style="color: black;">运用</span>,<span style="color: black;">因此</span><span style="color: black;">必须</span>一个面向一二线客服的平台,章鱼工作台就诞生了。章鱼工作台是基于qiankun微应用搭建的,其子应用最<span style="color: black;">起始</span><span style="color: black;">运用</span>Vue3、Vite和Ant Design,那时,<span style="color: black;">倘若</span>要在章鱼工作台中<span style="color: black;">拜访</span>客服订单详情页属于跨应用、跨技术栈通信,<span style="color: black;">运用</span>iframe是成本最小,<span style="color: black;">亦</span>是初期最合适的一种方式,这<span style="color: black;">亦</span>是页面复用的</span><strong style="color: blue;"><span style="color: black;"><span style="color: black;">第1</span>个<span style="color: black;">周期</span>:在子应用<span style="color: black;">运用</span>多个iframe容器嵌入工单系统中的订单详情页</span>。</strong></p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/cea08e0e07ca40d4a0199cede1bad789~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=a90eSxKsU5Sm59usY7uy4chMnm0%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">所有订单详情页的<span style="color: black;">运用</span>方只<span style="color: black;">必须</span>在本地创建iframe容器,<span style="color: black;">而后</span>在嵌入订单详情页的<span style="color: black;">拜访</span><span style="color: black;">位置</span>时传<span style="color: black;">有些</span>必要的参数如订单号、求购单号就能够正常<span style="color: black;">拜访</span>了,<span style="color: black;">非常</span><span style="color: black;">方便</span>。还<span style="color: black;">能够</span>支持<span style="color: black;">有些</span>高级配置供<span style="color: black;">运用</span>方<span style="color: black;">选择</span>,如支持<span style="color: black;">经过</span>url query传参的方式<span style="color: black;">掌控</span>页面样式,当用于<span style="color: black;">外边</span>嵌入时<span style="color: black;">隐匿</span>主应用的菜单和顶部tab栏等等。</span></p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/e0cd2d4c06f348b1b093ecba125b534b~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=nzAdLpg5uvzdpaYFrhRVcdKGOLY%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">这个<span style="color: black;">周期</span>,</span><strong style="color: blue;"><span style="color: black;">初步<span style="color: black;">处理</span>了页面复用的问题</span>。</strong>但<span style="color: black;">大众</span>都<span style="color: black;">晓得</span>iframe的<span style="color: black;">坏处</span>端,一二线客服<span style="color: black;">朋友</span>的<span style="color: black;">平常</span>工作中会<span style="color: black;">显现</span><span style="color: black;">海量</span>的页面切换,<span style="color: black;">这般</span>一来,iframe的内存占用高、加载缓慢的缺点就被放大开来,这个<span style="color: black;">周期</span>一二线客服经常会反馈页面卡顿,<span style="color: black;">因此</span>迫切<span style="color: black;">必须</span>进一步优化。</p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">2、单实例iframe搭配MF远程组件</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">对客服工单系统、章鱼工作台两个平台的用户特点、作业<span style="color: black;">行径</span>进行分析,<span style="color: black;">发掘</span>章鱼工作台的用户对页面的体验<span style="color: black;">需求</span>更高,于是对详情页做了<span style="color: black;">第1</span>次优化,步入了</span><strong style="color: blue;"><span style="color: black;">第二个<span style="color: black;">周期</span>:将订单详情页迁移至章鱼工单工作台,其构建方式<span style="color: black;">亦</span>由Vite变更为Webpack5,子应用之间利用Webpack5的Module Federation特性<span style="color: black;">经过</span>远程组件的方式进行数据通信</span>。</strong>另一方面,尽管iframe的缺点<span style="color: black;">显著</span>,但仍是跨技术栈应用间页面通信的不错<span style="color: black;">选取</span>,将iframe<span style="color: black;">掌控</span>在单实例容器中<span style="color: black;">能够</span>最大程度限制其对内存的占用。</p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/225e3b462c394ed1ab97694c5bea6f0f~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=JtTq4bSOFuLbBQuNKeoYlnuKle8%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">这般</span>一来,详情页的入口虽然有10多个,但通信方式都收拢<span style="color: black;">成为了</span>三种:远程组件、单实例iframe、本地组件。所有场景都能覆盖到,</span><strong style="color: blue;"><span style="color: black;">后续各个入口有<span style="color: black;">繁杂</span>交互的变更<span style="color: black;">或</span>自定义事件,都能够在页面主体做到监控和收口,不<span style="color: black;">必须</span>页面的<span style="color: black;">运用</span>方做额外<span style="color: black;">研发</span></span></strong>。</p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">3、技术实现</h1>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">3.1、单实例iframe通信</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">内容<span style="color: black;">供给</span>方</strong></p><span style="color: black;">详情接口响应后注册message事件。</span><span style="color: black;">监听iframe父级携带数据变化,更新本地页面数据。</span><span style="color: black;">本地页面交互事件被远端触发,发送当前的数据给远端做自定义交互。</span><span style="color: black;">/** Vue3 */</span>
<span style="color: black;">/** 1. 详情接口响应后注册message事件 */</span>
onMounted(<span style="color: black;"><span style="color: black;">()</span> =></span> {
<span style="color: black;">/** 请求详情接口 */</span>
fetchOrderDetail(<span style="color: black;"><span style="color: black;">()</span> =></span> {
<span style="color: black;">/** query上打上iframe标签,用于确定注册<span style="color: black;">机会</span> */</span>
route.query.iframeRoute && watchParentMessage()
})
})
<span style="color: black;">/** 2. 监听iframe父级携带数据变化,更新本地页面数据 */</span>
<span style="color: black;">const</span> watchParentMessage = <span style="color: black;"><span style="color: black;">()</span> =></span> {
<span style="color: black;">window</span>.addEventListener(<span style="color: black;">message</span>, <span style="color: black;"><span style="color: black;">event</span> =></span> {
<span style="color: black;">const</span> orderNo = event.data.data.orderNo
<span style="color: black;">if</span>(event.data.type ===<span style="color: black;">ORDER_CHANGE</span> && orderNo) {
<span style="color: black;">/** 更新订单信息*/</span>
initStream(orderNo)
}
})
}
<span style="color: black;">/** 3. 本地页面交互事件被远端触发,发送当前的数据给远端 */</span>
<span style="color: black;">window</span>.parent.postMessage(
<span style="color: black;">/** payload: 携带的数据*/</span>
{
<span style="color: black;">type</span>: <span style="color: black;">workbenchRoute</span>,
params: {
<span style="color: black;">/** <span style="color: black;">转</span>退货详情页 */</span>
name: <span style="color: black;">refundDetail</span>,
query: {
<span style="color: black;">// 携带数据</span>
},
},
},
<span style="color: black;">/** orgin: <span style="color: black;">倘若</span>想要传递给任意窗口,<span style="color: black;">能够</span>将这个参数设置为* ,为了安全起见,不<span style="color: black;">意见</span>设置为**/</span>
<span style="color: black;">*</span>
)<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">内容<span style="color: black;">运用</span>方</strong></p><span style="color: black;">页面初始化时注册message事件。</span><span style="color: black;">监听本地订单单号变化,将新的数据传给远端。</span><span style="color: black;">监听远端交互和数据变化,<span style="color: black;">按照</span>交互类型做<span style="color: black;">区别</span>的本地处理。</span><span style="color: black;">/** Vue2 */</span>
<span style="color: black;">/** 1. 页面初始化时注册message事件*/</span>mounted() {
window.addEventListener(<span style="color: black;">message</span>, <span style="color: black;">this</span>.callBack, <span style="color: black;">false</span>)
},
<span style="color: black;">/** 2. 监听本地订单单号变化,将新的数据传给远端*/</span>
watch: {
orderNo(newOrderNo) {
<span style="color: black;">/** 在iframe的contentWindow属性上挂载postMessage<span style="color: black;">办法</span>*/</span>
detailIframeRef.contentWindow.postMessage(
<span style="color: black;">/** payload: 携带的数据*/</span>
{
type: <span style="color: black;">ORDER_CHANGE</span>,
data: {
orderNo:newOrderNo,
<span style="color: black;">//其他数据</span>},
},<span style="color: black;">/** orgin: <span style="color: black;">倘若</span>想要传递给任意窗口,<span style="color: black;">能够</span>将这个参数设置为* ,为了安全起见,不<span style="color: black;">意见</span>设置为**/</span>
<span style="color: black;">*</span>,
)
},
},
<span style="color: black;">/** 3. 监听远端交互和数据变化,<span style="color: black;">按照</span>交互类型做<span style="color: black;">区别</span>的本地处理 */</span>
method: {
<span style="color: black;">/** callBack: 远端事件被触发后,处理本地回调<span style="color: black;">规律</span> */</span>
callBack(<span style="color: black;">event</span>) {
<span style="color: black;">try</span> {
<span style="color: black;">if</span> (<span style="color: black;">event</span>.data.type === <span style="color: black;">workbenchRoute</span>) {
<span style="color: black;">switch</span> (<span style="color: black;">event</span>.data.<span style="color: black;">params</span>.name) {
<span style="color: black;">case</span> <span style="color: black;">orderdetail</span>:
<span style="color: black;">//<span style="color: black;">转</span>订单详情的handler</span>
<span style="color: black;">break</span>
<span style="color: black;">case</span> <span style="color: black;">detail</span>:
<span style="color: black;">//跳转工单详情的handler</span>
<span style="color: black;">break</span>
<span style="color: black;">// 其他交互</span>
<span style="color: black;">default</span>:
<span style="color: black;">//兜底处理</span>
}
}
} <span style="color: black;">catch</span>(error) {
<span style="color: black;">//<span style="color: black;">反常</span>处理</span>
}
}<h1 style="color: black; text-align: left; margin-bottom: 10px;">3.2、远程组件通信</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">内容<span style="color: black;">供给</span>方</strong></p><span style="color: black;">配置webpack的MF插件,将<span style="color: black;">全部</span>订单详情页exposes出去</span><span style="color: black;"><span style="color: black;">守护</span>详情页的props</span><span style="color: black;">/** 配置webpack MF插件,将订单详情页exposes出去*/</span>
<span style="color: black;">new</span> <span style="color: black;">ModuleFederationPlugin</span>({
<span style="color: black;">filename</span>: <span style="color: black;">remoteEntry.js?</span>,
<span style="color: black;">library</span>: { <span style="color: black;">type</span>: <span style="color: black;">window</span>, <span style="color: black;">name</span>: <span style="color: black;">app_ticket</span> },
<span style="color: black;">name</span>: <span style="color: black;">app_ticket</span>,
<span style="color: black;">shared</span>: {
<span style="color: black;">/** 需要共享的依赖 */</span>
},
<span style="color: black;">exposes</span>: {
<span style="color: black;">/** <span style="color: black;">供给</span>订单详情远程组件*/</span>
<span style="color: black;">./OrderDetail</span>: <span style="color: black;">./src/views/orderdetail/Index.tsx</span>,
},
}),<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">内容<span style="color: black;">运用</span>方</strong></p><span style="color: black;">webpack配置<span style="color: black;">必须</span><span style="color: black;">意见</span>通信的远端应用</span><span style="color: black;"><span style="color: black;">运用</span>defineAsyncComponent注册组件</span><span style="color: black;">像本地组件<span style="color: black;">同样</span><span style="color: black;">运用</span>远程组件</span><span style="color: black;">/** 1.webpack配置远端应用 */</span>
remotes: {
app_ticket: getRemoteUrl(<span style="color: black;">app_ticket</span>),
},
<span style="color: black;">/** 2. <span style="color: black;">运用</span>defineAsyncComponent注册组件*/</span>
<span style="color: black;">OrderDetail</span>: defineAsyncComponent(<span style="color: black;"><span style="color: black;">()</span> =></span> <span style="color: black;">import</span>(<span style="color: black;">app_ticket/OrderDetail</span>)),
<span style="color: black;">/** 3. 像本地组件<span style="color: black;">同样</span><span style="color: black;">运用</span>远程组件*/</span>
<OrderDetail orderNo={orderNo} {...props} /><h1 style="color: black; text-align: left; margin-bottom: 10px;">4、总结</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">页面<span style="color: black;">运用</span>iframe的首屏耗时平均在7076ms,非首屏在2594ms,而MF的首屏只<span style="color: black;">必须</span></span><strong style="color: blue;"><span style="color: black;">1279ms</span></strong>,非首屏<span style="color: black;">更加是</span>只需<strong style="color: blue;"><span style="color: black;">428ms</span></strong>,渲染时间降低了<strong style="color: blue;"><span style="color: black;">6倍</span>。</strong></p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/6c75ffd464db441fa203b9b06fe9c8f6~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=ypjLK%2BbEL3KztNg84aQfHGZntxg%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">单个页面的内存占用减少到了之前的</span><strong style="color: blue;"><span style="color: black;">1/10</span></strong>以内,关于模块联邦和远程组件的<span style="color: black;">更加多</span>细节<span style="color: black;">能够</span>查看<a style="color: black;">Module Federation 在得物客服工单业务中的最佳实践</a>。</p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/c84ed4ceb18b482c9dc69a94021ceb40~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=iMFv1%2BrIOorl4Hc2TRYeAJxMG6k%3D" style="width: 50%; margin-bottom: 20px;"></div>
<h1 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">3、</span>首屏秒开优化</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">上一章节说到<span style="color: black;">运用</span>MF的方式<span style="color: black;">处理</span>了架构层面的卡顿问题,但无缓存下页面仍要2~3s<span style="color: black;">乃至</span>更久<span style="color: black;">才可</span>刷出订单信息,<span style="color: black;">此时</span>要怎么办?是的,<span style="color: black;">能够</span>改交互、拆接口。但<span style="color: black;">倘若</span>数据依赖了<span style="color: black;">海量</span>外域服务、<span style="color: black;">无</span>外域产研资源介入,且要在<span style="color: black;">1星期</span>时间做到有效的优化,那还能做些什么呢?</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">1、缓慢<span style="color: black;">原由</span></h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">因为</span><span style="color: black;">有些</span>历史<span style="color: black;">原由</span>,客服订单详情页<span style="color: black;">必须</span><span style="color: black;">同期</span>展示100+的订单信息,所有的订单信息、订单操作<span style="color: black;">触及</span>的字段接近200个,而</span><strong style="color: blue;"><span style="color: black;">这么多字段其中90%都在一个http接口里面,这个大接口<span style="color: black;">包括</span>了36个dubbo接口</span></strong>,这些接口来自交易正向、逆向、供应链、商家、商品、用户以及其他BU。并行的调用<span style="color: black;">必定</span>会<span style="color: black;">显现</span>短板效应,只要有一个接口RT(Reaction Time,响应时间)慢,就会拉慢<span style="color: black;">全部</span>http接口的响应速度,<span style="color: black;">同期</span><span style="color: black;">显现</span>Timeout的概率<span style="color: black;">亦</span>会<span style="color: black;">提升</span>,再加上页面本身对资源的渲染时间,无缓存下仍要2~3s<span style="color: black;">乃至</span>更久<span style="color: black;">才可</span>刷出订单信息。这个<strong style="color: blue;"><span style="color: black;">大接口的平均RT在500ms,P99线的RT达到了1.3s</span></strong>,下图<span style="color: black;">便是</span>生产环境下某一次的调用详情,耗时在782ms,降RT优化首屏渲染刻不容缓。</p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/cc7e65bc83ea4a9da944114b78ed298a~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=nxpBPjaxxYJ1yyi4gSNT4PXUmlo%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">除了接口RT耗时高的问题,还有首屏接口并行调用的问题。</span><strong style="color: blue;"><span style="color: black;">90%的字段都在一个大接口里面,剩下10%都是在零零散散的<span style="color: black;">有些</span>小接口里,把这些小接口加起来页面首屏接口超过6个</span>。</strong><span style="color: black;">咱们</span><span style="color: black;">晓得</span>一个Chrome页签最多并行处理6个http请求,<span style="color: black;">倘若</span>有第7个接口就会进入到Stalled(熄火)状态,等待前面的某一个接口响应完毕后再发起请求,下图是一个示例,getTrackTicketInfo接口是页面首屏的第7个接口,255.14ms<span style="color: black;">便是</span><span style="color: black;">必须</span>等待的时间。</p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p26-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/d362b844ad234c07af0d8a56504df3c1~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=KK%2BPqZvkaeqkL2AZPJjNwouqqU0%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">按照</span><span style="color: black;">以上</span>问题<span style="color: black;">状况</span>,</span><strong style="color: blue;"><span style="color: black;">初步的<span style="color: black;">方法</span><span style="color: black;">便是</span></span><span style="color: black;">接口先聚合再拆分</span></strong>,把所有接口的数据聚合到<span style="color: black;">一起</span>,<span style="color: black;">而后</span>再<span style="color: black;">按照</span>信息模块拆分成若干个接口,前端再<span style="color: black;">按照</span>业务场景和用户<span style="color: black;">行径</span>,去对拆分出来的接口的调用<span style="color: black;">机会</span>进行优化。<span style="color: black;">然则</span>,理想很<span style="color: black;">饱满</span>,现实很骨感,数据量摆在这,很难在<span style="color: black;">短期</span>去做到这件事情。光把字段梳理全,数据<span style="color: black;">源自</span>理清楚就用掉了两天时间,再<span style="color: black;">思虑</span>到成本和收益后,<span style="color: black;">咱们</span>的<strong style="color: blue;"><span style="color: black;"><span style="color: black;">最后</span><span style="color: black;">方法</span><span style="color: black;">便是</span></span><span style="color: black;">新增快慢接口</span>,</strong>快接口的RT要在200ms以内,所有拖慢RT的数据都放到慢接口中,<strong style="color: blue;"><span style="color: black;">前端再<span style="color: black;">按照</span>接口的特性将所有接口分为2个梯队在<span style="color: black;">区别</span>时间进行调用</span></strong>,最大程度的减少页面的首屏渲染时间。</p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">2、接口调用优化</h1>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.1、技术<span style="color: black;">方法</span></h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">为了<span style="color: black;">掌控</span>页面并行请求接口数量和页面数据渲染次数,将除了快慢接口之外,所有零散小接口分为如下</span><strong style="color: blue;"><span style="color: black;">两个梯队:不依赖详情大接口反参的首屏信息接口;依赖详情大接口反参的首屏信息接口、非首屏信息接口</span>。</strong></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">最后</span>详情页首屏接口调用<span style="color: black;">状况</span>示意图如下,在能够聚合依赖大接口反参的首屏信息接口的<span style="color: black;">状况</span>下,页面只会渲染两次,<span style="color: black;">第1</span>次是在快详情接口和<span style="color: black;">第1</span>梯队接口请求回来之后(<span style="color: black;">运用</span>Promise.all<span style="color: black;">掌控</span>数据的渲染<span style="color: black;">机会</span>),第二次<span style="color: black;">便是</span>在慢详情接口请求回来之后。</span></p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p26-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/5f0a1471120d48eb85f4598ab40402ec~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=0jkbEafdOg46qJaCQRzoQzwqbOA%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">运用</span>Promise.all来<span style="color: black;">保准</span>快详情接口和<span style="color: black;">第1</span>梯队的接口信息<span style="color: black;">同期</span>渲染,减少页面渲染次数,从而减少页面抖动的<span style="color: black;">状况</span>。Promise.all有个缺点<span style="color: black;">便是</span>其中有一个Promise<span style="color: black;">反常</span>,<span style="color: black;">全部</span>就会抛出<span style="color: black;">反常</span>,<span style="color: black;">因此</span><span style="color: black;">必须</span>对Promise.all包裹的Promise进行二次封装,<span style="color: black;">保准</span>有一个Promise报错不会干扰其他接口的请求,<span style="color: black;">详细</span>代码实现方式如下:</span></p><span style="color: black;">/** 处理promise,<span style="color: black;">保准</span>promise.all<span style="color: black;">运用</span>时相互独立 */</span>
<span style="color: black;">export</span> <span style="color: black;">const</span> handlerPromise = <span style="color: black;">(<span style="color: black;">api, params</span>) =></span> {
<span style="color: black;">return</span> <span style="color: black;">new</span> <span style="color: black;">Promise</span>(<span style="color: black;"><span style="color: black;">resolve</span> =></span> {
api(params)
.then(resolve)
.catch(<span style="color: black;"><span style="color: black;">()</span> =></span> resolve({ error: <span style="color: black;">true</span>}))
})
}<span style="color: black;">/** 详情页首屏请求函数 */</span>
<span style="color: black;">const</span> fetchOrderDetail = <span style="color: black;">(<span style="color: black;">callback?</span>) =></span> {
<span style="color: black;">/** <span style="color: black;">运用</span>handlerPromise封装过的promise,<span style="color: black;">保准</span>有一个报错不干扰其他接口请求 */</span>
<span style="color: black;">Promise</span>.all()
.then(<span style="color: black;">(<span style="color: black;"></span>) =></span> {
<span style="color: black;">// 快详情接口</span>!quickDetailData?.error && quickDetailHandler(quickDetailData)<span style="color: black;">// <span style="color: black;">第1</span>梯队接口调用:不依赖详情反参的首屏信息接口</span>!firstLevelData1?.error && firstLevelHandler1(firstLevelData1)
!firstLevelData2?.error && firstLevelHandler2(firstLevelData2)<span style="color: black;">// 执行回调</span>
nextTick(callback)
})
.then(<span style="color: black;"><span style="color: black;">()</span> =></span> {
<span style="color: black;">// 第二梯队接口调用:依赖详情反参的首屏信息接口、非首屏接口</span>
secondLevelHandler1()
secondLevelHandler2()
})
<span style="color: black;">// 执行慢接口</span>fetchSlowOrderDetail()
}<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">接口调用<span style="color: black;">次序</span>确认后还有一点<span style="color: black;">必须</span><span style="color: black;">重视</span>,<span style="color: black;">由于</span>慢接口响应耗时较高,在客服<span style="color: black;">朋友</span>快速<span style="color: black;">查找</span>的工作场景中,可能会在慢接口还在pending,就<span style="color: black;">已然</span>切换到下一个订单了,页面单实例的场景下,这个时候<span style="color: black;">倘若</span>不处理可能会将<span style="color: black;">显现</span>数据串台的<span style="color: black;">状况</span>,不属于该订单的数据<span style="color: black;">表示</span>了出来,关于这一点,<span style="color: black;">必须</span>在慢接口的handler上做如下处理。</span></p><span style="color: black;">/** 慢详情接口请求 */</span>
<span style="color: black;">const</span> fetchSlowOrderDetail = () => {
slowLoading.<span style="color: black;">value</span> = <span style="color: black;">true</span>
orderApi
.getDetail(<span style="color: black;">params</span>)
.then(slowData => {<span style="color: black;">/** 防止快速切换订单<span style="color: black;">引起</span>的数据串台问题 */</span>
<span style="color: black;">if</span> (slowData?.topInfo?.orderNo === orderNo.<span style="color: black;">value</span>) {
orderDetail.<span style="color: black;">value</span> = slowData
}
slowLoading.<span style="color: black;">value</span> = <span style="color: black;">false</span>})
.<span style="color: black;">catch</span>(() => {
slowLoading.<span style="color: black;">value</span> = <span style="color: black;">false</span>
})
}<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.2、<span style="color: black;">最后</span>效果</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">优化后</span></strong><span style="color: black;">的Waterfall图就如下所示,不会再<span style="color: black;">显现</span>灰色的stalled耗时了,<span style="color: black;">况且</span>在228ms后首屏的数据就<span style="color: black;">已然</span>请求回来了。</span></p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/aae077748be24b88b777fe279e11a204~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=pWqtJaKmSDkBdXNKRgUqgtkgccc%3D" style="width: 50%; margin-bottom: 20px;"></div>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">3、大接口优化</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">上面一点<span style="color: black;">处理</span>了首屏接口的调用问题,接下来是对大详情接口<span style="color: black;">详细</span>做的<span style="color: black;">有些</span>优化:</span></p><strong style="color: blue;"><span style="color: black;">接口协议由POST改为GET请求</span></strong>,GET的总耗时是POST的三分之二;Chrome下<span style="color: black;">倘若</span>检测到GET请求的是静态资源,则会缓存,<span style="color: black;">倘若</span>两次传输的数据相同,第二次以后耗费的时间将在10ms以内。另一方面<span style="color: black;">亦</span>为后续工作台引入Service Worker技术打下<span style="color: black;">基本</span>。<strong style="color: blue;"><span style="color: black;">新增快详情接口</span></strong>,将大接口中的响应耗时较高的字段整理出来,快接口<span style="color: black;">再也不</span><span style="color: black;">包括</span>这些字段。这些高耗时的字段新增字段级别的loading效果,为了避免快慢接口耗时差异<span style="color: black;">很强</span>,<span style="color: black;">引起</span><span style="color: black;">有些</span>经验丰富的客服<span style="color: black;">朋友</span>误以为快接口没返回数据的字段是空数据,<span style="color: black;">然则</span>这个loading数量不会超过3处,保持页面的整洁易读。<h1 style="color: black; text-align: left; margin-bottom: 10px;">4、总结</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">经过<span style="color: black;">以上</span>优化,快详情接口RT只<span style="color: black;">必须</span>平均</span><strong style="color: blue;"><span style="color: black;">190ms,从之前大接口的470ms下降了41%</span></strong>,首屏渲染时间从873ms降至<strong style="color: blue;"><span style="color: black;">376ms</span></strong><span style="color: black;">,</span><strong style="color: blue;"><span style="color: black;">下降了57%</span></strong>,95分位567ms,<strong style="color: blue;"><span style="color: black;">下降了62%</span></strong>。</p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/7b343a0fb3eb481d9775f2aec34e2714~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=2DWSyoq9fxGtDusIM%2Fa1KLAk3cc%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">首屏优化效果<span style="color: black;">显著</span>,很难再看到反馈详情页加载缓慢的VOC了,<span style="color: black;">必定</span>程度地<span style="color: black;">提高</span>了客服的平台体验满意度。</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">4、</span>信息编排、模版插拔能力建设</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">处理</span>了页面卡顿和首屏加载慢的问题,但仍存在<span style="color: black;">有些</span>问题。这一次在产研运<span style="color: black;">朋友</span>的通力协作下,<span style="color: black;">怎样</span>进一步<span style="color: black;">提高</span>技术<span style="color: black;">朋友</span>的<span style="color: black;">研发</span>体验和客服<span style="color: black;">朋友</span>的<span style="color: black;">运用</span>体验呢。</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">1、仍面临的问题</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">虽然详情页中堆叠的字段<span style="color: black;">已然</span>多达200处,随着业务高速发展仍会存在部分信息缺失、不准确的<span style="color: black;">状况</span>,对客服<span style="color: black;">平常</span>作业产生了<span style="color: black;">必定</span>的负向影响。另一方面,在<span style="color: black;">研发</span>订单类需求中,约60%的都是<span style="color: black;">协同</span>外域<span style="color: black;">或</span>内部进行字段增删改,<span style="color: black;">倘若</span><span style="color: black;">创立</span>了订单信息的编排能力,后续字段类需求将可配置,从而能够解放这部分需求的产研生产力,达到降本增效;<span style="color: black;">同期</span>若前端模块能够支持模块拔插能力,<span style="color: black;">亦</span>能为后续订单信息模块复用到坐席辅助及其他客服工作台<span style="color: black;">供给</span>技术支撑。</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">2、信息编排能力建设</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">将订单基本信息及<span style="color: black;">相关</span>信息<span style="color: black;">经过</span>统一Schema<span style="color: black;">守护</span></span>。</strong><span style="color: black;">大众</span><span style="color: black;">晓得</span>Schema(结构化的数据类型)只要约定的足够<span style="color: black;">繁杂</span>是<span style="color: black;">能够</span>用来描述所有场景的数据的,<span style="color: black;">因此</span><span style="color: black;">运用</span>Schema<span style="color: black;">第1</span>步<span style="color: black;">便是</span>要<span style="color: black;">掌控</span>好这个边界,在能够覆盖大部分业务场景前提下<span style="color: black;">不可</span>太<span style="color: black;">繁杂</span>。<span style="color: black;">首要</span>可将订单信息做3层细分:信息块、信息组、信息元素。做到配置信息块、信息元素<span style="color: black;">针对</span>订单详情页的场景<span style="color: black;">来讲</span>都不太合适,<span style="color: black;">因此</span><span style="color: black;">这儿</span><span style="color: black;">选取</span>约定到信息组的格式。</p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/6ccbad0f6f294d8ea567e66b1048efe0~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=AnXArPDr%2FcCZ%2FSFMWf%2FQKVBGD8w%3D" style="width: 50%; margin-bottom: 20px;"></div>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.1、Schema格式</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">上面图示中两组信息组可用下述Schema描述出来,</span><strong style="color: blue;"><span style="color: black;">利用数组的有序性,从左到右、从上到下对信息组进行渲染</span></strong>,实现订单信息的编排配置能力。</p><span style="color: black;">schemaData </span>: [
{
<span style="color: black;">label</span>: <span style="color: black;">订单类型</span>
text:<span style="color: black;">普通现货</span>
<span style="color: black;">children</span>: [
{
<span style="color: black;">id</span>: <span style="color: black;">orderTypeDetail</span>
<span style="color: black;">text</span>: <span style="color: black;">详情</span>,
<span style="color: black;">show</span>: true,
<span style="color: black;">toolType</span>: <span style="color: black;">linkBtn</span>, <span style="color: black;">/** linkBtn, primaryBtn, tag */</span>
<span style="color: black;">eventType</span>: <span style="color: black;">click</span>, <span style="color: black;">/** dbclick, hover*/</span>
<span style="color: black;">interactiveType</span>: <span style="color: black;">popover</span>, <span style="color: black;">/** modal, popover, message*/</span>
<span style="color: black;">children</span>: [
<span style="color: black;">//** popover弹出的内容 */</span>
{ <span style="color: black;">label</span>: , <span style="color: black;">text</span>: , <span style="color: black;">children</span>: <span style="color: black;">//..}]</span>
{ <span style="color: black;">label</span>: , <span style="color: black;">text</span>: }
]
},
{
<span style="color: black;">text</span>: <span style="color: black;">晚到必赔</span>,
<span style="color: black;">show</span>: true<span style="color: black;">toolType</span>: <span style="color: black;">tag</span>,
},
{
<span style="color: black;">text</span>: <span style="color: black;">退运服务</span>,
<span style="color: black;">show</span>: true
<span style="color: black;">toolType</span>: <span style="color: black;">tag</span>,
},
]
},
{
<span style="color: black;">id</span>: <span style="color: black;">tradeStatus</span>
<span style="color: black;">label</span>: <span style="color: black;">支付状态</span>
text:<span style="color: black;"><span style="color: black;">已然</span>支付</span>
<span style="color: black;">children</span>: [
{
<span style="color: black;">text</span>: <span style="color: black;">七天风控</span>,
<span style="color: black;">show</span>: true<span style="color: black;">toolType</span>: <span style="color: black;">tag</span>,
},
]
}
],<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.2高级配置</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">运用</span>Schema<span style="color: black;">能够</span>满足大部分的字段渲染场景,<span style="color: black;">然则</span><span style="color: black;">针对</span><span style="color: black;">有些</span><span style="color: black;">繁杂</span>的交互和自定义的样式仍<span style="color: black;">必须</span>前端去实现,这个时候<span style="color: black;">每一个</span>信息元素中的id就发挥了<span style="color: black;">功效</span>,前端<span style="color: black;">能够</span></span><strong style="color: blue;"><span style="color: black;"><span style="color: black;">按照</span>id去绑定交互事件和自定义样式</span></strong>,<span style="color: black;">详细</span>实现如下:</p><span style="color: black;">/** 信息元素枚举*/</span>
<span style="color: black;">enum</span> INFO_ElEMENT_MAP {
<span style="color: black;">/** 订单类型详情按钮 */</span>
ORDERTYPE_DETAIL: <span style="color: black;">orderTypeDetail</span>
}
<span style="color: black;">/** 信息元素*/</span>
<span style="color: black;">const</span>infoElementMap = {
INFO_ElEMENT_MAP.ORDERTYPE_DETAIL: {<span style="color: black;">/** 绑定事件 */</span>
onClick: <span style="color: black;"><span style="color: black;">()</span> =></span> {
orderTypeDetailClickHandler()
},
<span style="color: black;">/** 绑定样式 */</span>
className: ,
},
<span style="color: black;">/** 其他<span style="color: black;">必须</span>添加<span style="color: black;">繁杂</span>交互和样式*/</span>
}<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.3、模版解析</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">约定好了Schema和规范,</span><strong style="color: blue;"><span style="color: black;">前端再编写对应模版解析代码去渲染页面</span></strong>,对应渲染图如下所示。</p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p26-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/c586ee08d19a4755ac8f95324da6aecf~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=0t%2BYjCeV56wDbxMZlVg18yYmnko%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">最外层的渲染器代码如下:</span></p>const SchemaRender = () => {
//TODO 健壮性代码
return (
<span style="color: black;"><<span style="color: black;">div</span>></span>
{schemaData.length ? (
<span style="color: black;"><<span style="color: black;">Row</span>></span>{schemaTemplate.map(item => {
// 分隔符
if (item.key === TemplateKeyEnum.dividedLine) {
return<span style="color: black;"><<span style="color: black;">Divider</span> /></span>
}
return (
<span style="color: black;"><<span style="color: black;">Col</span> <span style="color: black;">span</span>=<span style="color: black;">{12}</span>></span>
<span style="color: black;"><<span style="color: black;">InfoItem</span>
<span style="color: black;">key</span>=<span style="color: black;">{item.key}</span>
<span style="color: black;">label</span>=<span style="color: black;">{item.label}</span>
<span style="color: black;">text</span>=<span style="color: black;">{item.text}</span>
<span style="color: black;">infoList</span>=<span style="color: black;">{item.children.map(child</span> =></span>{
return {
text: popoverRender(child),
hide: !child.show,
}
})}
/><span style="color: black;"></<span style="color: black;">Col</span>></span>
)
})}
<span style="color: black;"></<span style="color: black;">Row</span>></span>
) : (
<span style="color: black;"><<span style="color: black;">Skeleton</span> <span style="color: black;">title</span>=<span style="color: black;">{false}</span> <span style="color: black;">active</span> <span style="color: black;">paragraph</span>=<span style="color: black;">{{</span> <span style="color: black;">rows:</span> <span style="color: black;">3</span> }} /></span>
)}
<span style="color: black;"></<span style="color: black;">div</span>></span>
)
}<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">最后</span>,Schema加上模版渲染就能渲染出订单详情页的信息,</span><strong style="color: blue;"><span style="color: black;">后续此类型的需求除了和外域约定字段,就<span style="color: black;">再也不</span><span style="color: black;">必须</span>额外资源投入了</span>。</strong></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">3、模块插拔能力建设</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">实现了信息快速编排,还有信息模块高耦合的问题。</span><strong style="color: blue;"><span style="color: black;"><span style="color: black;">并不</span>同角色的客服<span style="color: black;">朋友</span>关注的信息是不<span style="color: black;">同样</span>的,<span style="color: black;">因此</span>新的订单详情页要<span style="color: black;">按照</span>客服的身份去展示<span style="color: black;">区别</span>的信息</span></strong>;<span style="color: black;">况且</span>随着屏幕<span style="color: black;">体积</span>的<span style="color: black;">区别</span>,所适合布局<span style="color: black;">亦</span><span style="color: black;">区别</span>。另一方面,<strong style="color: blue;"><span style="color: black;">工单详情、坐席辅助都<span style="color: black;">必须</span>展示订单信息的某一个信息模块</span></strong>(<span style="color: black;">全部</span>页面展示就太重了),<span style="color: black;">此时</span>就<span style="color: black;">必须</span>订单信息模块有可插拔的能力了。</p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">3.1、技术<span style="color: black;">方法</span></h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">初步<span style="color: black;">方法</span>是后端<span style="color: black;">守护</span>一个信息模块池,<span style="color: black;">供给</span>出一个接口,前端<span style="color: black;">经过</span>传一个标识,能够返回对应标识<span style="color: black;">必须</span>的模块组合,<span style="color: black;">而后</span><span style="color: black;">按照</span>数据组合渲染数据。这个<span style="color: black;">方法</span><span style="color: black;">能够</span>实现信息可拔插能力。</span></p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/a166d66c947b4c68a00fb50b00f8a192~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=HiXoVKaJD8DwT08I8%2BB7CjGR0b4%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">以上</span><span style="color: black;">方法</span><span style="color: black;">能够</span><span style="color: black;">处理</span>问题,<span style="color: black;">亦</span>比较简单,<span style="color: black;">然则</span><span style="color: black;">掌控</span>数据的还是前端,这其实违背了最初建设信息编排能力的初衷。于是<span style="color: black;">最后</span>改为后端<span style="color: black;">朋友</span>从客服<span style="color: black;">朋友</span>的登录态拿到userId,<span style="color: black;">按照</span>id拿到其所在处理组,是买家处理组就返回买家版订单信息,卖家版就返回卖家版订单信息。另一方面,前端<span style="color: black;">亦</span><span style="color: black;">按照</span>屏幕<span style="color: black;">体积</span>做布局的自适应。</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">3.2、<span style="color: black;">最后</span>效果</h1><span style="color: black;">大屏下页面布局:</span>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/42fa267c9dc8491b9244086664d0103a~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=%2FrFtuX%2BFB5AWKSFJOkFA44fpu8k%3D" style="width: 50%; margin-bottom: 20px;"></div><span style="color: black;">小屏下页面布局(1440*900以下):</span>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/7407171ee1e8476997cddf23e38ff7f6~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=Fur6YiEGbC%2BonU74WfoJfPDRncA%3D" style="width: 50%; margin-bottom: 20px;"></div><span style="color: black;">工单详情<span style="color: black;">运用</span>订单详情中的物流记录、服务记录订单信息模块:</span>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/afc56ae370c743c1a3881d04367d18d3~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=RpPu0Hh2mMGWMRC9J%2FK1mpgFrS0%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">从改版<span style="color: black;">败兴</span>近8个迭代的资源投入数据来看,</span><strong style="color: blue;"><span style="color: black;">订单需求<span style="color: black;">研发</span>成本降低了66.7%</span>。</strong></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">5、</span>灰度和埋点<span style="color: black;">方法</span></h1>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">1、灰度<span style="color: black;">方法</span></h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">新版详情页改动<span style="color: black;">很强</span><span style="color: black;">必须</span><span style="color: black;">按照</span>客服所在处理组进行灰度,<span style="color: black;">然则</span>一线和二线的处理组分配又不太<span style="color: black;">同样</span>,</span><strong style="color: blue;"><span style="color: black;"><span style="color: black;">因此</span><span style="color: black;">必须</span><span style="color: black;">按照</span>入口<span style="color: black;">源自</span>判断<span style="color: black;">运用</span>哪套AB<span style="color: black;">方法</span>接口</span></strong>。另一方面,订单详情页的入口非常多,<span style="color: black;">因此</span>在<span style="color: black;">每一个</span>入口做灰度不太现实,改动<span style="color: black;">很强</span>,<span style="color: black;">因此</span><span style="color: black;">选取</span><strong style="color: blue;"><span style="color: black;">收口到详情页主页面区分新老页面</span></strong><span style="color: black;">。</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">1.1、技术<span style="color: black;">方法</span></h1><span style="color: black;"><span style="color: black;">按照</span><span style="color: black;">源自</span>区分<span style="color: black;">运用</span>一线AB<span style="color: black;">方法</span>还是二线AB<span style="color: black;">方法</span>,伪代码如下:</span><span style="color: black;">/** 获取<span style="color: black;">源自</span>区分IM、工单灰度组信息 */</span>watch(
() => props.platformCode,
code => {<span style="color: black;">try</span> {
<span style="color: black;">switch</span> (code) {
<span style="color: black;">case</span> PLATFORM_TYPE.IM:
<span style="color: black;">/** 一线灰度走一线灰度接口 */</span>
isGray.<span style="color: black;">value</span> = <span style="color: black;">true</span>
<span style="color: black;">break</span>
<span style="color: black;">case</span> PLATFORM_TYPE.TICKET:
<span style="color: black;">/** 二线灰度走二线灰度接口 */</span>
isGray.<span style="color: black;">value</span> = <span style="color: black;">true</span>
<span style="color: black;">break</span>
<span style="color: black;">default</span>:
isGray.<span style="color: black;">value</span> = <span style="color: black;">false</span>
} <span style="color: black;">catch</span> {
isGray.<span style="color: black;">value</span> = <span style="color: black;">false</span>
}
},
{
immediate: <span style="color: black;">true</span>,
}
)<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">在主页面<span style="color: black;">按照</span>灰度<span style="color: black;">状况</span>渲染详情模版:</span></p>return () => isGray.value ? (
<span style="color: black;"><></span>
<span style="color: black;"><<span style="color: black;">Button</span> <span style="color: black;">type</span>=<span style="color: black;">"link"</span> <span style="color: black;">onClick</span>=<span style="color: black;">{clickHandler}</span> ></span>
返回{isOld.value ? 新版 : 老版}
<span style="color: black;"></<span style="color: black;">Button</span>></span>
{isOld.value ? <span style="color: black;"><<span style="color: black;">OldDetail</span> {<span style="color: black;">...props</span>} /></span> : <span style="color: black;"><<span style="color: black;">Detail</span> {<span style="color: black;">...props</span>} /></span>}
<span style="color: black;"></></span>
) : <span style="color: black;"><<span style="color: black;">OldDetail</span> {<span style="color: black;">...props</span>} /></span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">1.2、总结</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">按照</span>培训进度开放灰度名单给客服<span style="color: black;">运用</span>新版页面,<span style="color: black;">同期</span>对新老版页面的数据进行监控 。支持可监控、可灰度、可回滚,<span style="color: black;">保证</span>了在页面大改动<span style="color: black;">状况</span>下的系统质量稳定。</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">2、埋点<span style="color: black;">方法</span></h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">为了<span style="color: black;">表现</span>订单信息优化的收益和价值,<span style="color: black;">必须</span>对客服<span style="color: black;">朋友</span>在新老订单详情页的停留时间、跳出订单详情页次数进行比对。</span></p><strong style="color: blue;"><span style="color: black;">订单详情页停留时间</span></strong>:有效的停留时间越长<span style="color: black;">必定</span>程度能说明页面的查阅费力度越高。<strong style="color: blue;"><span style="color: black;">订单详情页跳出率</span></strong>:跳出率越高说明当前订单详情信息<span style="color: black;">不可</span>满足客服的查阅需求,<span style="color: black;">必须</span>去其他页面查看。是信息不全、不清晰的一种<span style="color: black;">表现</span>。<span style="color: black;">况且</span>跳出页面会重新加载新的页面,等待时间会长于页面内获取信息,<span style="color: black;">增多</span>客服获取信息的时间。<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.1、页面停留时间</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">运用</span>监听路由的<span style="color: black;">办法</span>去计算页面停留时间。<span style="color: black;">这儿</span>只对其中一种做分析,其他两种类似。</span></p><span style="color: black;">确定路由:https://xxx-xxx.xxx/orderdetail/:id</span><span style="color: black;">只<span style="color: black;">必须</span><span style="color: black;">思虑</span>上一个路由是订单页面的<span style="color: black;">状况</span></span><span style="color: black;">数据过滤:<span style="color: black;">少于</span>3s,大于30min视为无效数据</span><span style="color: black;"><span style="color: black;">倘若</span><span style="color: black;">近期</span>的路由是订单页面,则重置时间</span><span style="color: black;">/** 数据上报 */</span>
<span style="color: black;">const</span> uplog = <span style="color: black;">(<span style="color: black;">current, last, constant, <span style="color: black;">type</span></span>) =></span> {
<span style="color: black;">/** b: 只用<span style="color: black;">思虑</span>上一个路由是订单页面的<span style="color: black;">状况</span> */</span>
<span style="color: black;">if</span>(constant === last) {<span style="color: black;">const</span> nowTime = getNowTime()
<span style="color: black;">const</span> stayTime = nowTime - stayOrderDetailTime.currentTime
<span style="color: black;">/** c: <span style="color: black;">少于</span>3s,大于30min视为无效数据 */</span>
<span style="color: black;">if</span> (stayTime > <span style="color: black;">3000</span> && stayTime < <span style="color: black;">1000</span> * <span style="color: black;">60</span>*<span style="color: black;">30</span>) {
orderDuLog(<span style="color: black;">ORDER_STAY_TIME</span>, {
orderNo: orderNo.value,
stayTime,
<span style="color: black;">type</span>,
})
}
stayOrderDetailTime.currentTime = nowTime
}<span style="color: black;">/** d:<span style="color: black;">倘若</span><span style="color: black;">近期</span>的路由是订单页面,则重置时间*/</span>
<span style="color: black;">if</span>(constant === current) {
stayOrderDetailTime.currentTime = getNowTime()
}
}<span style="color: black;">/** 监听路由 */</span>
watch(
<span style="color: black;"><span style="color: black;">()</span> =></span> {
<span style="color: black;">return</span> { name: route.name, id: route.params?.id }
},
throttle(
<span style="color: black;">(<span style="color: black;">currentRoute, lastRoute</span>) =></span> {
<span style="color: black;">/** 从工单出发:只用<span style="color: black;">思虑</span>上一个路由是订单页面的<span style="color: black;">状况</span> */</span>
uplog(currentRoute?.name, lastRoute?.name, <span style="color: black;">`<span style="color: black;">${globalConfig.backstageCode}</span>_orderdetail`</span>, <span style="color: black;">routeChange</span>)
},
<span style="color: black;">100</span>,
{ leading: <span style="color: black;">true</span>, trailing: <span style="color: black;">false</span> }
),
{
deep: <span style="color: black;">true</span>,
immediate: <span style="color: black;">true</span>,
}
)<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.2、页面跳出次数</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">页面跳出次数就比较简单了,只<span style="color: black;">必须</span>在跳出事件的handler里加上数据上报<span style="color: black;">办法</span>,<span style="color: black;">例如</span>查看商品详情、退换货详情、用户分期信息、工单详情等等,最后计算跳出总量<span style="color: black;">就可</span>。</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.3、总结</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">老版页面平均停留时间15.6s,新版页面的平均停留时间8.5s,</span><strong style="color: blue;"><span style="color: black;">客服每次<span style="color: black;">查找</span>信息的时长缩短7.1s,可<span style="color: black;">按照</span>详情页PV换算日均可降低客服<span style="color: black;">朋友</span>工作时长</span>。</strong></p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/c92efec98889486ca937b9aa4474a1b6~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=YliqypwSQtSaEbfEk3j%2Bd2bAYe0%3D" style="width: 50%; margin-bottom: 20px;"></div>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">同期</span>,客服<span style="color: black;">查找</span>特定订单信息时<span style="color: black;">必须</span>跳到别的页面<span style="color: black;">查找</span>,这说明订单信息是有缺失和<span style="color: black;">或</span>客服是对信息准确性是有<span style="color: black;">可疑</span>的,老版页面跳出率11.4%(约8.7次<span style="color: black;">拜访</span>跳出1次),新版页面跳出率7.92%(约12.6次<span style="color: black;">拜访</span>跳出1次)。</span><strong style="color: blue;"><span style="color: black;">客服查看订单信息时跳出的率<span style="color: black;">亦</span>下降3.48pp</span></strong>。</p>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/d617e3b63f98404f840d482819acc3c6~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=KzytWW3%2FeR3wNOh%2BaR8ALjpicQE%3D" style="width: 50%; margin-bottom: 20px;"></div>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-6w9my0ksvp/9a16650d617143c68b425cf9b93c8239~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1723649713&x-signature=tAryiu4yUiWCZ85wrih0ew5yQoY%3D" style="width: 50%; margin-bottom: 20px;"></div>
<h1 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">6、</span>总结&规划</h1>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">1、总结</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">关于动态路由页面的多平台复用:</span></strong><span style="color: black;">跨技术栈<span style="color: black;">运用</span>单实例的iframe通信,<span style="color: black;">协同</span>双向的postMessage事件监听用户<span style="color: black;">行径</span>触发交互;微应用内<span style="color: black;">运用</span>Module Federation通信,在<span style="color: black;">保证</span>客服<span style="color: black;">运用</span>体验的<span style="color: black;">同期</span>,节省了<span style="color: black;">研发</span><span style="color: black;">守护</span>成本。</span></p><span style="color: black;">MF的首屏<span style="color: black;">必须</span></span><strong style="color: blue;"><span style="color: black;">1279ms</span></strong>,非首屏只需<strong style="color: blue;"><span style="color: black;">428ms</span></strong>,渲染时间降低了<strong style="color: blue;"><span style="color: black;">6倍</span>。</strong><span style="color: black;">单个页面的内存占用减少到了之前的</span><strong style="color: blue;"><span style="color: black;">1/10</span></strong>以内。<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">关于大数据量的页面首屏优化:</span></strong><span style="color: black;">基于业务优化接口调用<span style="color: black;">机会</span>,<span style="color: black;">保准</span><span style="color: black;">同期</span>不超过6个接口请求,避免<span style="color: black;">显现</span>Stalled耗时,对大接口RT进行优化,场景<span style="color: black;">准许</span>的话可改为GET协议类型,降低首屏响应时间,<span style="color: black;">提高</span>客服体验。</span></p><span style="color: black;">首屏请求6个以上接口时<span style="color: black;">再也不</span><span style="color: black;">显现</span>Stalled耗时,大接口改为GET后总耗时是POST的</span><strong style="color: blue;"><span style="color: black;">2/3</span></strong>。<span style="color: black;">快详情接口RT只<span style="color: black;">必须</span>平均</span><strong style="color: blue;"><span style="color: black;">190ms</span>,</strong>从之前大接口的470ms<strong style="color: blue;"><span style="color: black;">下降了41%</span></strong>,首屏渲染时间从873ms降至<strong style="color: blue;"><span style="color: black;">376ms</span></strong>,<strong style="color: blue;"><span style="color: black;">下降了57%</span></strong>,95分位567ms,<strong style="color: blue;"><span style="color: black;">下降了62%</span></strong>。<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">关于信息编排、模块拔插能力建设:</span></strong><span style="color: black;"><span style="color: black;">按照</span>业务分析字段特点,约定合适的Schema格式使得信息内容可灵活配置;对用户的职能特点、设备<span style="color: black;">状况</span>进行分析,使得用户所<span style="color: black;">拜访</span>页面的布局、内容做到区分,做到给用户看到合适的内容,降低坐席的<span style="color: black;">查找</span>信息的费力度。</span></p><span style="color: black;">订单需求<span style="color: black;">研发</span>成本能够</span><strong style="color: blue;"><span style="color: black;">降低66.7%</span></strong>。<span style="color: black;">老版页面平均停留时间15.6s,新版页面的平均停留时间8.5s,客服每次<span style="color: black;">查找</span>信息的时长</span><strong style="color: blue;"><span style="color: black;">缩短7.1s</span></strong>,<span style="color: black;">按照</span>订单详情页的PV可换算出<strong style="color: blue;"><span style="color: black;">每日可降低客服<span style="color: black;">朋友</span>的<span style="color: black;">查找</span>时长</span></strong>。<span style="color: black;">老版页面跳出率11.4%(约8.7次<span style="color: black;">拜访</span>跳出1次),新版页面跳出率7.92%(约12.6次<span style="color: black;">拜访</span>跳出1次)。客服查看订单信息时跳出率</span><strong style="color: blue;"><span style="color: black;">下降了3.48pp</span>。</strong>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">2、后续规划</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">虽然客服订单详情页的<span style="color: black;">运用</span>体验<span style="color: black;">已然</span>得到<span style="color: black;">提高</span>,<span style="color: black;">然则</span>体验升级之路仍在继续:</span></p><span style="color: black;">模块联邦虽然<span style="color: black;">火速</span>,<span style="color: black;">然则</span>对公共依赖<span style="color: black;">守护</span>成本<span style="color: black;">很强</span>,<span style="color: black;">亦</span>会<span style="color: black;">引起</span>应用构建速度下降。后续会基于无界对订单子应用进行迁移,建设专门存放远程组件的应用容器,<span style="color: black;">提高</span>子应用的秒开和快速切换体验,<span style="color: black;">同期</span><span style="color: black;">亦</span>能<span style="color: black;">提高</span>工单子应用构建速率,解耦横向订单功能的发布。可期待后续内容。</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">*文 / 昌禾</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">本文属得物技术原创,<span style="color: black;">更加多</span>精彩<span style="color: black;">文案</span>请看:<a style="color: black;">得物技术</a></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">未经得物技术许可严禁转载,否则依法追究法律责任!</span></p>
期待更新、坐等、迫不及待等。 回顾历史,我们感慨万千;放眼未来,我们信心百倍。 软文发布平台 http://www.fok120.com/
页:
[1]