关注前端早早聊,跟进第三十届|前端早早聊大会 BFF 专场(GraphQL、统一网关、API 接入管理、超大规模集群,协议转换、安全切面、高并发、可视化编排、统一稳定性建设...)8-14 全天直播,9 位讲师,点击报名看直播👉 ):前端
前端早早聊大会,与掘金联合举办。加 codingdreamer 进大会技术群,赢在新的起跑线, 全部往期都有全程录播,上手年票一次性解锁所有web
本文是第十八届 - 前端早早聊性能优化专场,也是早早聊第 127 场,来自 阿里 飞猪-太吾 的分享。算法
你们好,我是来自飞猪的胡昊,花名是太吾。先不着急开始,由于我刚才在小助手的朋友圈中看到前几位导师分享的截图,同时看到你们的一些问题。有人说我这篇分享在掘金中有对应的文章,相信也有很多小伙伴可能看过那篇文章,我想说的是看到过那篇文章还要不要听我这边分享,我以为仍是要听的。小程序
文章主要的做用是一个传播,而一些干货确定仍是在 PPT 中,因此你们仍是不要放过前端早早聊 2020 年最后一次分享。前两位大佬都是比较偏硬核:IDE 和可视化。咱最后又回到了传统的 H5 上的一个性能优化,可能没有前两位那么硬核,可是但愿能够给你们带来一些启发。后端
这个 PPT 也是以前用于咱们集团内的一个分享,因此有点偷懒,其实大部份内容是差很少的,可是有一些对外仍是须要有一些具体的讲解。本次分享是《飞猪双 11 - 基于 Web 的性能优化》,双 11 我当时的一个职责是性能的 pm,因此对双 11 总体的 Web 性能优化仍是有必定的理解,但愿把这个理解带给你们。缓存
整个会分为三个部分来说解。安全
首先是背景。从 Weex 到 Web 是基于什么样的考虑?性能优化
咱们飞猪从 2013 年第一个 H5 页面的落地一直到 2016 年总体切换成 Weex,不管是 Weex 仍是 Rax 总体都是以 Weex 渲染为主,在飞猪端和手淘端内。一直到 2020 年的 6 月,咱们又总体顺应集团的策略又切换回 H5,技术栈也做为了统一,总体使用了 Rax1.0 的一个技术栈。微信
以前可能有 Rax 的同窗来前端早早聊分享过。咱们怎样基于这样一个考虑从 Weex 切换到 H5,咱们对于Weex 性能的可信度仍是比 H5 要好的。但为何要从一个相对来讲好一点的 Weex 技术栈切换到 H5?主要是基于如下几点考虑:markdown
这是一个总体的背景。
在基于这个背景下,H5 性能确定是比 Weex 性能相对来讲要差一点。以前刚切换的 H5 以后,两次大促(618 大促和国庆),飞猪的会场性能 IOS 大概在 1.5 秒,安卓大概在 2 秒左右。相对比淘系 618 会场的性能 1.4 秒和 2.1 秒,相对来讲是差很少的。你们基本上都是把通用的优化手段都用尽了,须要进入一个深水区。对于飞猪双11 的目标是 IOS 1.2 秒,安卓 1.6 秒,总体是要提高大概 20% 这样一个水平。在通用手段已经用尽的状况下,还要提高 20%,这样也是一个很是大的挑战。
还有在飞猪这个场景下:
针对这些困难,视野要从前端这边就是脱离开来,站在是多职能协同的一个方向,主要借助于客户端以及服务端的一些能力,来进行一个总体的优化。
总体的一个优化思路,先说一个通用的优化思路:
基于这些通用手段你们都想到了,你们都确定必定都会用完的,而用完以后的效果就好比以前提到的像 61八、国庆大促已是一个顶峰,而以后想再进行优化,就要脱离这些进行更进一步的优化。增进式手段就有如下这些:
主要就是这 4 点来进行一个双 11 大促的场景的保障。
总体思路用渲染流程来看,块条对应上面的渲染流程能够精简的部分。能够看到从上到下 SSR、Snapshop 和预渲染效果会愈来愈好,可是它适用的场景确定也是愈来愈少的。这个以后具体会提到。相似一些客户端预加载、资源的离线缓存、数据的变形请求和模块的缓存,这都是一些通用的手段,是跟客户端集成已经用了好久了。
总体的主要思路,以前也说到的就是压力转移,把客户端的压力转化到服务端上去。一些缓存、依赖于客户端的能力、阶段的变形以及最后在对用户进行一些体感上的优化,给用户最优秀的体验。
首先说一下预渲染。以前讲师也提到预加载,可能飞猪这边作的更激进一点,能够先看一下右边这个效果。左边开启预渲染以后,点击就相似主会场这样一个胶囊,跳转过去基本上秒开,没有任何渲染的过程那种感受。而右边未开启预渲染就会有白屏、Loading 以及模块的加载这样一个过程,很明显的一个对比。
什么是预渲染?客户端以“离屏”的方式来初始化好容器并 LoadUrl,在上屏以前就完成了页面的 Rasterization(光栅化)。即客户端直接把 URL 经过 Webview 在后台 Load 好,等咱们须要的时候,它直接把 Webview 进行一个上屏的操做就行了,因此作的是比较激进一点。可是为了是对于主会场这种重点保障,仍是在端侧这边作了这样一个能力,体验是比较好。
预渲染它有什么特色?
可是这样一个预渲染方案上了以后,FCP(首屏首次渲染时间)就从 1~2 秒,一直到了前端这边的 100 毫秒,在客户端那边的打点基本上在 50~60 毫秒,就能够完成一个页面的展现,至关之快。
总体的一个方案的设计,咱们会有一个相似 Orange 这样一个动态下发的平台,去配置一些咱们想要预渲染的一个URL,它就会动态下发到一个用户的 APP 上,APP 获取到这些配置以后,就会在后台这边去加载这样一个 URL,而且解析页面,完成页面的光栅化以后,置入缓存池,咱们还会启动一个内存预警的监控,保障 APP 的运行稳定,若是有 crash 风险,咱们会自动释放缓存池中页面,咱们确定仍是保稳定性为主,设计了这样一个内存管控。
当用户真实的去访问 H5 页面的时候,咱们会检测用户 是否命中了预渲染的 URL 配置。咱们会有一个 URL域名,以及 URL query 的一些特殊化的参数,进行 key 的对比。若是命中了以后,就会经过 URL 做为 key,在缓存池中找到 Webview,直接进行一个上屏的操做,GPU 直接进行上屏的显示。由于用客户端在后台已经渲染好这个页面确定跟前端的一些逻辑不相符合,因此咱们须要在真实的上屏以后,客户端会派发一个 document 事件来通知 H5 页面渲染完成以后,前端监听这个事件以后,咱们会进行一些对于性能埋点的处理、页面埋点的处理以及最后那些动态投放的一些事件的处理,这些都是在前端须要进行兼容的地方。
作完这些以后,这一个页面的总体展现逻辑就完成了。在用户退出这个页面以后,咱们会清除对应的 Webview 缓存,而且在 300 毫秒后马上又在后台从新去启动这样一个新的 Webview 去加载这个页面,从新的去进行下一次的这样一个总体流程。
预渲染这样一个方案比预加载只加载一个 Webview 容器,不去请求真实的数据,可能会更加激进一点。可是效果也会相对来讲更好一点。
第二个方案就是 SSR。重启 SSR 是为了什么?通常如今在集团内基本上 SSR 它的定义,从本来的 Server-side-render 慢慢转移到 Serverless-side-render,顺应 Serverless 这样一个大潮,反正慢慢的发现 SSR 可用武之地。咱们这种不是传统意义上的 SSR,跟传统意义上 SSR 就是相似 PC 时代这种主文档,就直接返回HTML主文档的那种 SSR。
咱们不一样的点是看底下这样两个渲染流程的对比,上面就是传统的 CSR 的渲染流程,在借助客户端的文档缓存以及数据的预加载,以后就进行模块的 JS 和渲染模块。而咱们这边,经过这个图你们能够看到咱们的 SSR 是在接口中返回的 HTML,在接口返回 HTML 后,咱们去把 HTML 再异步 hydrate 到页面上去,咱们至关因而省掉了后面加载模块 JS 和渲染模块这样一个流程,由于把 HTML 放在接口中返回,因此接口多是会比日常会更慢一点。咱们认为把 HTML 直接塞到页面中去,大概会花 10 毫秒左右的时间。这样,总体在减掉后面模块JS 加载和渲染模块的时间,咱们这边大概会节省 700 毫秒~800 毫秒的时间,SSR 相对于 CSR 这样一个对比。
整个渲染流程的改变,为何是基于这样一个考虑,而不是把在传统意义上在主文当中直接返回整个页面的结构,而是在接口返回的时候,返回这样一个 HTML 来再进行一个渲染。
这背后的思考主要是基于这样一个考虑:以前手淘那边也作了这样一个方案,他们当时作了同步 SSR 放在主文档中返回。他们当时就发现有同步 SSR 后,一个是白屏时间会变得长,由于它没法使用客户端的一些能力,例如离线包以及数据预加载这样两个客户端提供了很好的一个能力。咱们就跟进了异步 SSR方案,也就是放在接口中返回一个 HTML 这样一个方式。
它有几个优势:
咱们基于改形成本最小化的这样一个原则:
完成这些考虑以后,咱们就成功地上了 SSR 方案,也获得了不错的效果,基本上是从以前的 1~2 秒用了 SSR 以后基本上平均耗时能够降到 1 秒如下。
页面快照。先看右边的效果,开启了 Snapshot 以后,就没有 Loading 的环节,直接点开页面,页面就直接进行一个相似直出的效果。Snapshot 实际上的效果确定是比 SSR 要好的,可是咱们有了 Snapshot 为何还要 SSR?
针对这个页面快照,咱们这边是设计了两种方案。一种方案是接口缓存,一种方案是传统意义上的 HTML 缓存。为何会有这两种方案的并存?
一种会场天天都会变阵,其实你看双11或者双12,你去逛会场,天天模块的顺序以及模块的数据展现逻辑,运营天天都会去进行修改的。因此天天都会变的状况下,若是是采用了 HTML 缓存,就不可避免的带来一些闪动的问题。例如你昨天访问了这个页面,今天再访问这个页面,它可能中间有几个模块没有了,或者有几个商品,它的坑位从 4 个变成了 6 个,这样你进去以后,它整个页面都会啪啪啪乱闪一气,而且就这种闪动过程,它其实会可能会带来不少毛病,一些不可预知的问题。例如就是模块可能会重复的渲染,而且有些模块它可能就会错位这样一个特别玄学的一些问题。
因此咱们又设计了第二个接口缓存的一个方式,接口缓存配合上模块缓存,基本上也能够作到性能和直接 HTML 缓存这样性能保持基本一致。由于接口缓存配合模块缓存数据相对来讲固定,就避免了闪动,而且咱们为什么有并存这样一个东西,咱们会发现 HTML 缓存也并不是毫无用武之地,就相似右边这种场景,所有会场这种场景,他在整个大促期间基本上是不会变更的。因此就采用 HTML 缓存带来更高更快的一个加载效率,是可使用 HTML 缓存。
整个的方案设计以下:
再提两点,一些设计上的思路:
最后一点就是 SPA。咱们慢慢的在页面中的一些优化,给用户的体验也很好了。可是页面间的一个切换的体验还不是很好。由于以前其实你看到底下是有 Tabbar。可是它实际上是多个页面,你若是像以前那种方式去切换底部的 Tab,其实它整个是一个页面的跳转,是 replace 方式,整个页面都会进行一个刷新,这样体验是很是很差的。
在双 11 的时候,咱们对它进行了一个改进。底部 bar 是总体一个包框,咱们经过点击底部 bar 切换的时候,咱们仅须要去获取数据。仍是刚才提到那个点,咱们的页面是经过数据进行获取到模块,经过模块拼装组成的。因此咱们只须要知道模块有哪些,咱们就能够把页面组成起来。因此咱们切换 tab 的时候,咱们只须要去获取数据,去获取到模块,把页面的 DOM 替换一下,咱们就能够完成到页面的这样一个切换,而不用整个的 replace。
为何基于 SPA 实现,仍是刚才说到那个点。
咱们初版设计开启了 SPA 以后,咱们就获取那个模块的数据,替换当前 tab 对应的模块,进行页面的更新。可是咱们发现这样有一个问题:若是总体去不停的去替换模块,仍是比较卡顿的。相对于直接传统意义上咱们心目中那种单页应用仍是有一点鸿沟,因此咱们就对它进行了升级。
咱们只缓存首屏的 DOM,减小数据获取的过程。而且在高端机上咱们会请求首个 tab 数据渲染完成以后,咱们会去预加载其余几个 tab 的数据。这样下次切换过去的时候就没有数据获取过程,咱们能够直接取用它。就至关于把多页面之间的数据同时都拿到以后,咱们切 tab 就能够造成丝滑般的切换效果。咱们只须要隐藏其余 Tab 容器内 DOM。把该展现的那些 DOM 给 display 出来就行了。
最后再提两个小点,以前讲师他们也说到。基本上每一个优化都要借助客户端离线能力,离线包和数据的并行请求,我看基本上是 H5 这边是每次都会用到的。
可是就说一点小的设计,咱们对于会场页面是设计了一个 **URL + package **方式,咱们会在信鸽,就是咱们一个后台去输入须要进行离线的页面,在会场这种场景下。咱们信鸽就会在后台跑一个 puppetter,把页面的资源给获取到,而且再经过一些滚屏的操做,把一些懒加载的资源也给获取到。就把整个资源打成一个资源包,最后经过一个hash的方式,在去真实页面访问的时候,进行匹配。
第二点,数据并行请求的这样一个部分,咱们设计了相对于正常的 Memory 命中和 Miss 不命中这样一个状态下,咱们还设计了一个 Ongoing 这样一个状态。咱们认为只要客户端发起请求,那必定是比前端真实发起请求要快的要提早的,由于实际它确定是要提早的,因此咱们就会等待就是客户端真实的请求返回以后,咱们再会拿客户端的那样一个数据,而不是从新发起一次请求。
整个这边就不那么细说了,反正最终达成了咱们当时这样一个目标,基于咱们以前说到的不管是通用手段也好,仍是一些增进手段也好。通用手段可能也是提供了很大的一个帮助,增进手段在它的基础上有个更高的一个提高。反正最终是达成这样一个目标,而且有了这些东西以后,咱们会有一些将来可期的这样一种感受。
性能优化,慢慢的就会发现它从前端的这样一个职能慢慢的上升到多职能协同的这样一种方式。慢慢你若是去优化,你确定就慢慢不能站在前端的这样一个视角,慢慢的就会依赖于就相似前面说的 NSR 还有服务端这种 SSR 以及咱们如今还有那种 ESR 就是 CDN 边缘计算这样去的一些就是东西,就慢慢你会发现性能优化慢慢是超脱了前端这样一个单纯的职能这样一个方面,你要站在多智能协同方式进行性能优化的尝试。
规划就不那么细说提几点:
这样等等一系列的内功提高,以及咱们飞猪这边目标是前端的两秒达标率要达到 90%。因此单纯的单业务,咱们端内的单业务固然就须要去拓展到多业务。咱们就想法是有一个优化手段及如今在集团内咱们是有跨端性能小组是有白皮书这样一个方式,去记录一些优化手段,慢慢去 push 各个业务,进行落地,而且去收集各个业务的一些好的优化的手段,来进行沉淀反哺,慢慢去把总体的性能给提升起来。
最后惯例推荐一本书,这边推荐的就是《金字塔原理》,它是讲一个相似写 PPT 或者是思考表达和解决方式的这样一种逻辑。写 PPT、写文章之类的这样一种逻辑,是一套就是逻辑清晰、重点突出、井井有条,简单易懂的思考表达方式和规范动做。这本书我以为是挺好的。看了以后对于作 PPT 或者是写文章,都是由很多的帮助的。你们有兴趣的能够去看一下。
最后惯例中的惯例,确定是须要招人的。咱们团队关因而飞猪的用户前端和数字化经营团队,咱们的业务是关于旅游的一切咱们均可以去尝试。咱们团队的基础事项。以前有咱们团队的南路,也来分享过 Web Flutter 这样一个方案,咱们团队的有 Flutter,那么以及在咱们如今 SSR 也是咱们团队基于 Serverless 这样一个大潮去作的。还有一些中后台的微前端,以及一体化的开发以及端线互动,以及智能搭建这样一个东西,咱们团队技术思想都是包括的。 因此基本上各个方面你们都有包括,因此你们有兴趣就等你了,就能够经过邮箱,P六、P7 多多益善。
你们也能够关注一下咱们飞猪技术的公众号,Fliggy F2E 以及掘金,有些以前看到我这篇文章有在掘金上发,也是被咱们飞猪前端这边专栏去收藏。若是对跨端这边性能这边有想法的,也能够加我微信了解一下。
关注前端早早聊,跟进学习更多 BFF/GraphQL,请关注第三十届|前端早早聊大会 BFF 专场 - 玩转先后端接口(GraphQL、统一网关、API 接入、API 管理、协议转换、统一安全切面、高并发处理、可视化编排、统一稳定性建设...)8-14 全天直播,9 位讲师,报名上车看直播👉 ):