面试官:你解决过哪些难题-预渲染/SSR/SPA/离线包/Snapshot

5,612 阅读32分钟

关注前端早早聊,跟进第三十届|前端早早聊大会 BFF 专场(GraphQL、统一网关、API 接入管理、超大规模集群,协议转换、安全切面、高并发、可视化编排、统一稳定性建设...)8-14 全天直播,9 位讲师,点击报名看直播👉 ):

海报 (1).png

前端早早聊大会,与掘金联合举办。加 codingdreamer 进大会技术群,赢在新的起跑线, 所有往期都有全程录播,上手年票一次性解锁全部


本文是第十八届 - 前端早早聊性能优化专场,也是早早聊第 127 场,来自 阿里 飞猪-太吾 的分享。

自我介绍

大家好,我是来自飞猪的胡昊,花名是太吾。先不着急开始,因为我刚才在小助手的朋友圈中看到前几位导师分享的截图,同时看到大家的一些问题。有人说我这篇分享在掘金中有对应的文章,相信也有不少小伙伴可能看过那篇文章,我想说的是看到过那篇文章还要不要听我这边分享,我觉得还是要听的。

文章主要的作用是一个传播,而一些干货肯定还是在 PPT 中,所以大家还是不要放过前端早早聊 2020 年最后一次分享。前两位大佬都是比较偏硬核:IDE 和可视化。咱最后又回到了传统的 H5 上的一个性能优化,可能没有前两位那么硬核,但是希望可以给大家带来一些启发。

这个 PPT 也是之前用于我们集团内的一个分享,所以有点偷懒,其实大部分内容是差不多的,但是有一些对外还是需要有一些具体的讲解。本次分享是《飞猪双 11 - 基于 Web 的性能优化》,双 11 我当时的一个职责是性能的 pm,所以对双 11 整体的 Web 性能优化还是有一定的理解,希望把这个理解带给大家。

目录

C18-7 太吾-如何在双11大促中实现会场页面秒开.002.jpeg

整个会分为三个部分来讲解。

  • 背景
  • 优化的方向。主要的优化手段就是右边你看到的这 6 个东西,具体内容后面具体讲解。
  • 总结和规划

背景

首先是背景。从 Weex 到 Web 是基于什么样的考虑?

技术栈演进

C18-7 太吾-如何在双11大促中实现会场页面秒开.004.jpeg

我们飞猪从 2013 年第一个 H5 页面的落地一直到 2016 年整体切换成 Weex,无论是 Weex 还是 Rax 整体都是以 Weex 渲染为主,在飞猪端和手淘端内。一直到 2020 年的 6 月,我们又整体顺应集团的策略又切换回 H5,技术栈也作为了统一,整体使用了 Rax1.0 的一个技术栈。

之前可能有 Rax 的同学来前端早早聊分享过。我们怎样基于这样一个考虑从 Weex 切换到 H5,我们对于Weex 性能的可信度还是比 H5 要好的。但为什么要从一个相对来说好一点的 Weex 技术栈切换到 H5?主要是基于以下几点考虑:

  • 第一,我们认为 H5 的研发体验一定是最好的,并且在飞猪端内升级 UC 的 U4 内核和 WKWebview 之后,性能我们认为和 Native 的差距是逐渐的缩小,所以我们可以尝试去进行 H5 的渲染;
  • 第二,针对之前支付宝小程序的策略,对于小程序的开发场景越来越多,而小程序的开发动态性它是不足的,因为它传统的开发意义和 H5 的体系是比较割裂的,是需要开发两套代码。如果一个页面要分别投小程序和 H5 的话,需要双倍的开发成本,我们是比较无法接受的,毕竟人力那么宝贵;
  • 第三,我们还是希望去统一端技术的方案,希望有一套代码可以多端投放,支持 H5、小程序,以及未来的 Flutter。其实已经是现在的 Flutter;
  • 第四,Rax1.0 也是可以支持 Weex,为什么没有编译成 Weex?因为 Weex 和小程序都有其需要开发兼容的地方,它都是一个对于传统 API 的子集以及一些单独的 API。所以我们如果同时要适配 Weex 和小程序,对于开发来说是灾难性的。底下有一个开发难度的简单对比,单纯的开发 H5是没有限制的,相信很多小伙伴很乐意去开发,但是小程序它是有一定的限制。如果同时开发 Weex 加小程序,两端的同时兼容,那将是无法接受的。而如果是 H5 加小程序,也只需要去单纯的适配一个小程序就可以完成。这样是相对可以接受的。

这是一个整体的背景。

面临的困难

C18-7 太吾-如何在双11大促中实现会场页面秒开.005.jpeg

在基于这个背景下,H5 性能肯定是比 Weex 性能相对来说要差一点。之前刚切换的 H5 之后,两次大促(618 大促和国庆),飞猪的会场性能 IOS 大概在 1.5 秒,安卓大概在 2 秒左右。相对比淘系 618 会场的性能 1.4 秒和 2.1 秒,相对来说是差不多的。大家基本上都是把通用的优化手段都用尽了,需要进入一个深水区。对于飞猪双11 的目标是 IOS 1.2 秒,安卓 1.6 秒,整体是要提升大概 20% 这样一个水平。在通用手段已经用尽的情况下,还要提升 20%,这样也是一个非常大的挑战。

还有在飞猪这个场景下:

  • 飞猪会场的模块复杂。运营业务方都针对于旅游场景有很多的想法,比如头图这边一定是要有视频的,去吸引别人去玩。以及飞猪这边互动动画模块。还有飞猪榜单类型,也有一些榜单的聚合模块,这些模块都是比较复杂的。有些是前端耗时、有些算法耗时。
  • 接口 RT 比较高。并且服务端是没有办法优化的。类似榜单这种场景,它是多榜单聚合,有榜单的个性化,并且算法那边想要去加多种模型,去更加的拉高它的 RT,理论可以为点击率带来一定的提升,你也没办法反驳别人。所以你只能让它任由的把 RT 升高,而你毫无办法。
  • 旅行行业的一些特点特征。我们的一些个性化或者是一些模块,都比较依赖于定位信息以及用户信息来给大家推相应的一些商品,定位信息和用户信息会更加的拖慢一个首屏的时间,所以这就是整个优化所面临的一些困难。

优化方向

针对这些困难,视野要从前端这边就是脱离开来,站在是多职能协同的一个方向,主要借助于客户端以及服务端的一些能力,来进行一个整体的优化。

优化思路

C18-7 太吾-如何在双11大促中实现会场页面秒开.007.jpeg

整体的一个优化思路,先说一个通用的优化思路:

  • 第一阶段白屏。整个比如说类似一个页面,它的打开的这样一个进度,从一开始的白屏,主要就是进行一个 Webview 初始化以及主文档下载,基础 JS 下载。前几位讲师基本上提到这些过程,前端优化手段肯定是依赖于客户端的缓存,以及减少资源包的大小这些通用手段;
  • 第二阶段 Loading 情况。这边基本上就是发生数据请求的这样一个阶段,在这个阶段可以使用的通用手段,就类似服务端优化,请求拆分,把一个页面的数据可以分解成首屏和非首屏这样一个思路。首屏渲染,尽量少的 DOM,尽量少的模块以及一些数据预加载。之前说的数据并行以及客户端那边并行发起数据请求方式。之前几位讲师也有提到这里就不细说了;
  • 最后阶段模块上屏。慢慢的有元素可以往屏上进行加载。这段时间它主要发生的就是模块 JS 加载以及模块渲染。这里的通用手段基本上也就是对于模块 JS 精简以及就是对于模块的缓存。这里提一点,我们会场基本上是搭建的场景,搭建是一个什么概念?就是一个底部的页面的 Layout 上面可以把它想象成根据参数从服务端获取需要某个页面需要哪些模块,再异步的去拉那些模块下来,把数据灌入那些模块再进行展示,是这样一个思路。类似于你现在把你的一个通用型页面,把它拆分成很多个模块去进行渲染,渲染哪些模块是由服务端的数据来决定的,比较类似搭建这样的一个场景。

基于这些通用手段大家都想到了,大家都肯定一定都会用完的,而用完之后的效果就比如之前提到的像 618、国庆大促已经是一个顶峰,而之后想再进行优化,就要脱离这些进行更进一步的优化。增进式手段就有以下这些:

  • 预渲染。这个是重点保障一个主会场的打开效果。具体的实现之后会提到;
  • SSR。前几个讲师也有提到,我们现在在 C 端场景可能 SSR 提的就比较少了,用的比较少了。但现在又重提SSR 这是为什么?也是为了提高秒开率。之前 Weex 的情况下,其实一直都是提秒开率的,但是切换到 H5 之后,可能确实没有 Weex 当时这么好,所以我们需要借助一些 SSR 这样的东西去提升我们的页面秒开率;
  • Snapshot。类似前几位讲师说的页面快照,把页面的一些数据或者是页面 HTML 直接储存下来。在真实数据到来之前,提前展示一个页面结构,可以大大提前用户的可视时间,让用户不这么焦急等待;
  • SPA。单页应用这样一个东西。把多个页面聚合,保障页面间的跳转顺滑,来提升用户的体感。

主要就是这 4 点来进行一个双 11 大促的场景的保障。

C18-7 太吾-如何在双11大促中实现会场页面秒开.008.jpeg

整体思路用渲染流程来看,块条对应上面的渲染流程可以精简的部分。可以看到从上到下 SSR、Snapshop 和预渲染效果会越来越好,但是它适用的场景肯定也是越来越少的。这个之后具体会提到。类似一些客户端预加载、资源的离线缓存、数据的变形请求和模块的缓存,这都是一些通用的手段,是跟客户端集成已经用了很久了。

整体的主要思路,之前也说到的就是压力转移,把客户端的压力转化到服务端上去。一些缓存、依赖于客户端的能力、阶段的变形以及最后在对用户进行一些体感上的优化,给用户最优秀的体验。

预渲染

C18-7 太吾-如何在双11大促中实现会场页面秒开.009.jpeg

首先说一下预渲染。之前讲师也提到预加载,可能飞猪这边做的更激进一点,可以先看一下右边这个效果。左边开启预渲染之后,点击就类似主会场这样一个胶囊,跳转过去基本上秒开,没有任何渲染的过程那种感觉。而右边未开启预渲染就会有白屏、Loading 以及模块的加载这样一个过程,很明显的一个对比。

什么是预渲染?客户端以“离屏”的方式来初始化好容器并 LoadUrl,在上屏之前就完成了页面的 Rasterization(光栅化)。即客户端直接把 URL 通过 Webview 在后台 Load 好,等我们需要的时候,它直接把 Webview 进行一个上屏的操作就好了,所以做的是比较激进一点。但是为了是对于主会场这种重点保障,还是在端侧这边做了这样一个能力,体验是比较好。

预渲染它有什么特点?

  • 无感直出。很明显的一个体验;
  • 端侧定制。这可能是因为是跟端侧比较耦合,可能现在只有飞猪端内可以使用这样一个能力;
  • 少量页面。目前是只给主会场用了,因为你想想一个 APP 后台去一直启动这样一个 Webview,它肯定比较耗内存,并且是可能会引起一些 crash 风险的。所以只能配少量的页面,多了肯定是 crash 率可能会越来越高。

但是这样一个预渲染方案上了之后,FCP(首屏首次渲染时间)就从 1~2 秒,一直到了前端这边的 100 毫秒,在客户端那边的打点基本上在 50~60 毫秒,就可以完成一个页面的展示,相当之快。

方案设计

C18-7 太吾-如何在双11大促中实现会场页面秒开.010.jpeg

整体的一个方案的设计,我们会有一个类似 Orange 这样一个动态下发的平台,去配置一些我们想要预渲染的一个URL,它就会动态下发到一个用户的 APP 上,APP 获取到这些配置之后,就会在后台这边去加载这样一个 URL,并且解析页面,完成页面的光栅化之后,置入缓存池,我们还会启动一个内存预警的监控,保障 APP 的运行稳定,如果有 crash 风险,我们会自动释放缓存池中页面,我们肯定还是保稳定性为主,设计了这样一个内存管控。

当用户真实的去访问 H5 页面的时候,我们会检测用户 是否命中了预渲染的 URL 配置。我们会有一个 URL域名,以及 URL query 的一些特殊化的参数,进行 key 的对比。如果命中了之后,就会通过 URL 作为 key,在缓存池中找到 Webview,直接进行一个上屏的操作,GPU 直接进行上屏的显示。因为用客户端在后台已经渲染好这个页面肯定跟前端的一些逻辑不相符合,所以我们需要在真实的上屏之后,客户端会派发一个 document 事件来通知 H5 页面渲染完成之后,前端监听这个事件之后,我们会进行一些对于性能埋点的处理、页面埋点的处理以及最后那些动态投放的一些事件的处理,这些都是在前端需要进行兼容的地方。

做完这些之后,这一个页面的整体展示逻辑就完成了。在用户退出这个页面之后,我们会清除对应的 Webview 缓存,并且在 300 毫秒后立刻又在后台重新去启动这样一个新的 Webview 去加载这个页面,重新的去进行下一次的这样一个整体流程。

预渲染这样一个方案比预加载只加载一个 Webview 容器,不去请求真实的数据,可能会更加激进一点。但是效果也会相对来说更好一点。

SSR

C18-7 太吾-如何在双11大促中实现会场页面秒开.011.jpeg

第二个方案就是 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 这样一个对比。

方案设计

C18-7 太吾-如何在双11大促中实现会场页面秒开.012.jpeg

整个渲染流程的改变,为什么是基于这样一个考虑,而不是把在传统意义上在主文当中直接返回整个页面的结构,而是在接口返回的时候,返回这样一个 HTML 来再进行一个渲染。

这背后的思考主要是基于这样一个考虑:之前手淘那边也做了这样一个方案,他们当时做了同步 SSR 放在主文档中返回。他们当时就发现有同步 SSR 后,一个是白屏时间会变得长,因为它无法使用客户端的一些能力,例如离线包以及数据预加载这样两个客户端提供了很好的一个能力。我们就跟进了异步 SSR方案,也就是放在接口中返回一个 HTML 这样一个方式。

它有几个优点:

  • 减少渲染前的模块 Load 的时间消耗。就是模块那边基本上数据返回回来之后,我们就可以进行一个页面的展示,而不用等模块在进行一个拉取以及模块的渲染;
  • 渲染就放在了服务端上,可以规避高低端机容器的影响。在高端机上可能就是渲染以及模块拉取这种都可能影响还不大。但对于低端机来说,对于一些模块的拉取和渲染,这是非常耗时的。而如果把渲染放在服务端上,就可以规避掉这样一个高低端机容器的影响;
  • 可以复用客户端的一个性能优化的能力。这样我们可以使用客户端提供的离线包以及数据预加载的这样一个能力,就不会浪费客户端的一些能力。

我们基于改造成本最小化的这样一个原则:

  • 基于现有的搭建的链路,仅仅增加一个 SSR render 的链路;
  • 可以做到 CSR 到 SSR 的平滑的切换;
  • 仅需要判断 HTML 是否返回,就可以切换到不同的链路去进行渲染,并且模块可以基本复用,这样就形成一个改造成本非常小的SSR 效果。

遇到的困难

C18-7 太吾-如何在双11大促中实现会场页面秒开.013.jpeg

  • 一个就是如何进行平滑的切换,就是 SSR 如果出现了问题怎么办?怎么降级回去?基于考虑,所以我们只需要在前端这边判断接口有没有返回 HTML,就可以走到不同的链路上去,这是一个比较直接就可以解决问题的方法;
  • 前端稳定性的一些考虑。因为 SSR 肯定有很多模块,它可能就是用的一些变量,或者是用的一些异步,可能在服务端那边拿不到模块的具体的一个数据,这样返回的时候可能会出现类似报错或者类似一开始这个模块没有展示出来,之后在 Web 端在 Hydrate 的时候再展示出来,像一个页面闪动这样一个情况。这样对业务模块进行一个整体的就是升级,一个是在 SSR 层做一些变量的兜底,以及对模块进行一些类似占位这样的一个处理,保证页面初始化跟 hydrate 最小更新;
  • 对于沉浸式 titlebar 的一个支持。沉浸式 titltbar 肯定是要依赖客户端的一些变量,就客户端的 navbar 的高度是沉浸式 titltbar 的一个必要的参数,而 SSR 肯定是获取不到客户端参数的。所以我们后来发现在 innerHTML 的时候,是有间隙可以获取到这样一个 titlebar 高度的,我们在这个时候再通过 style 去动态设置这样一个高度就可以实现沉浸式 titlebar 的一个支持;
  • 最后一点,因为我们现在搭建这边都是通过统一渲染页。无论是离线、数据预加载以及一些模块缓存都是有一个统一渲染页这样一个东西。而类似这样一个统一渲染页,它进行离线了之后,它里面的就是 SSR 的配置,就会固定在那里,就无法针对于单页面,就是相当于你所有的页面要开 SSR 就全开 SSR。我们有些页面肯定不一定适配好了,或者是基于流量的考虑,不可能所有页面都开 SSR 的。所以我们得再加一层拦截去确定 是走SSR 链路还是普通的 CSR 链路。我们就去进行一个域名的拦截,通过判断后面的 query 来判断它是否在白名单中。在白名单中就走 SSR 链路,否则就走 CSR 链路。

完成这些考虑之后,我们就成功地上了 SSR 方案,也得到了不错的效果,基本上是从之前的 1~2 秒用了 SSR 之后基本上平均耗时可以降到 1 秒以下。

Snapshot

C18-7 太吾-如何在双11大促中实现会场页面秒开.014.jpeg

页面快照。先看右边的效果,开启了 Snapshot 之后,就没有 Loading 的环节,直接点开页面,页面就直接进行一个类似直出的效果。Snapshot 实际上的效果肯定是比 SSR 要好的,但是我们有了 Snapshot 为什么还要 SSR?

  • 首先我们在营销页面这样一个场景下,回访率是比较低的。一个页面用户第二次去打开这个页面的概率仅为10%~30%。所以 Snapshot 它缓存那些数据,它的命中率也就只有 10%~30% 这样一个运动率;
  • 其次就是 Snapshot 适合的是一种非千人千面的场景。有些东西类似前几位讲师也有说到,就是一个商品的时效性的问题,所以有些场景就不适合用 Snapshot。

针对这个页面快照,我们这边是设计了两种方案。一种方案是接口缓存,一种方案是传统意义上的 HTML 缓存。为什么会有这两种方案的并存?

一种会场每天都会变阵,其实你看双11或者双12,你去逛会场,每天模块的顺序以及模块的数据展示逻辑,运营每天都会去进行修改的。所以每天都会变的情况下,如果是采用了 HTML 缓存,就不可避免的带来一些闪动的问题。例如你昨天访问了这个页面,今天再访问这个页面,它可能中间有几个模块没有了,或者有几个商品,它的坑位从 4 个变成了 6 个,这样你进去之后,它整个页面都会啪啪啪乱闪一气,并且就这种闪动过程,它其实会可能会带来很多毛病,一些不可预知的问题。例如就是模块可能会重复的渲染,并且有些模块它可能就会错位这样一个特别玄学的一些问题。

所以我们又设计了第二个接口缓存的一个方式,接口缓存配合上模块缓存,基本上也可以做到性能和直接 HTML 缓存这样性能保持基本一致。因为接口缓存配合模块缓存数据相对来说固定,就避免了闪动,并且我们为何有并存这样一个东西,我们会发现 HTML 缓存也并非毫无用武之地,就类似右边这种场景,全部会场这种场景,他在整个大促期间基本上是不会变动的。所以就采用 HTML 缓存带来更高更快的一个加载效率,是可以使用 HTML 缓存。

方案设计

C18-7 太吾-如何在双11大促中实现会场页面秒开.015.jpeg

整个的方案设计如下:

  • **HTML 缓存。**它的优点就是展现的速度快,操作简单,并且它的劣势就是在模块不确定的环情况下,页面可能会闪,但是它适用场景就类似全部会场这种。HTML 缓存就类似大家可以理解成你在所有的页面展示完成之后,你去存一个首屏的一个 DOM 到缓存中去,等下次你进入这个页面,你首先去缓存中取这样一个 HTML,先把它给塞到屏幕上去,先给它做上屏的操作。等真实的数据回来之后,在对这样一个界面进行一个 hydrate 操作;
  • **接口缓存。**为什么接口缓存跟页面快照有关系。因为刚才说到搭建这样一个场景,有哪些模块其实都是接口去进行返回的,数据也是接口返回的。所以我们只要把接口缓存下来,我们就知道这个页面它有哪些模块,并且那些模块的数据是什么,只要把这个接口缓存下来,我们就可以通过这个接口直接把页面进行一个展示。它的优点就是页面的展示很稳定,但是劣势就是相较于 HTML 缓存,它的展示会相对来说较慢一点,并且接口缓存它把整个页面的一个JS,就是整个接口都给缓存下来,相较于缓存 HTML,它缓存的占用空间会很大,但它适用的场景就更多了。我们的一些主要的会场,例如超级宝贝、榜单会场以及特色会场,这些都是使用了这样一个接口缓存的页面快照方式。

再提两点,一些设计上的思路:

  1. 第一个就是 HTML 缓存中,类似我们有一些时效性的那些商品坑位,我们不想进行一个 HTML 的保存,DOM 的保存,我们就可以自定义一些 class name。去给那些模块设置上,到保存的时候,我们会识别这些 class name,去把它进行一个剔除,或者是只保存父节点这样一个方式,来进行一个时效性的问题解决。还有大家可以基于这样一个 class name 的设计,我们可以设计一些类似横滑列表,我们只保存前几项,或者是类似头图 banner,我们只保存第一项就好了。这样一个减少 HTML 缓存的大小以及效率设计;
  2. 第二个缓存总控。如果缓存无限制的去塞,那肯定是不行的。我们肯定是要设计一个缓存的总控来控制缓存的数量。我们用 LRU (算法)慢慢的去剔除掉使用的最少以及最远进行访问的一些缓存的数据,把新的给缓存进来,整体控制一个最大数,我们当时应该是当时应该是有缓存最多 8 个。超过 8 个之后就会进行一些剔除的一些判断,这样就保证一个缓存的稳定性。

SPA

C18-7 太吾-如何在双11大促中实现会场页面秒开.016.jpeg

最后一点就是 SPA。我们慢慢的在页面中的一些优化,给用户的体验也很好了。但是页面间的一个切换的体验还不是很好。因为之前其实你看到底下是有 Tabbar。但是它其实是多个页面,你如果像之前那种方式去切换底部的 Tab,其实它整个是一个页面的跳转,是 replace 方式,整个页面都会进行一个刷新,这样体验是非常不好的。

在双 11 的时候,我们对它进行了一个改进。底部 bar 是整体一个包框,我们通过点击底部 bar 切换的时候,我们仅需要去获取数据。还是刚才提到那个点,我们的页面是通过数据进行获取到模块,通过模块拼装组成的。所以我们只需要知道模块有哪些,我们就可以把页面组成起来。所以我们切换 tab 的时候,我们只需要去获取数据,去获取到模块,把页面的 DOM 替换一下,我们就可以完成到页面的这样一个切换,而不用整个的 replace。

为什么基于 SPA 实现,还是刚才说到那个点。

  • 搭建页面已经形成比较成熟的体系,就是我们的页面框架,它是共用一套 solution/core-render 的,它不会关联页面,就是业务的模块,它背后的 Layout 它所有的页面都是一个,只是上面的模块不同,你所以看到的页面不同,其余的后面的 Layout 永远都是一样的;
  • 第二点每个页面业务模块它都是通过数据获取的,这两个都是必要条件才可以进行这样一个 SPA 的切换。它通过数据获取模块,我们只需要进行一个 DOM 的切换,就可以进行一个页面间的一个跳转,跳转回去的时候,我们只需要缓存模块,就可以形成无感的切换效果。

优化演进

image.png

我们第一版设计开启了 SPA 之后,我们就获取那个模块的数据,替换当前 tab 对应的模块,进行页面的更新。但是我们发现这样有一个问题:如果整体去不停的去替换模块,还是比较卡顿的。相对于直接传统意义上我们心目中那种单页应用还是有一点鸿沟,所以我们就对它进行了升级。

我们只缓存首屏的 DOM,减少数据获取的过程。并且在高端机上我们会请求首个 tab 数据渲染完成之后,我们会去预加载其他几个 tab 的数据。这样下次切换过去的时候就没有数据获取过程,我们可以直接取用它。就相当于把多页面之间的数据同时都拿到之后,我们切 tab 就可以形成丝滑般的切换效果。我们只需要隐藏其他 Tab 容器内 DOM。把该展示的那些 DOM 给 display 出来就好了。

资源&数据预缓存

C18-7 太吾-如何在双11大促中实现会场页面秒开.018.jpeg

最后再提两个小点,之前讲师他们也说到。基本上每个优化都要借助客户端离线能力,离线包和数据的并行请求,我看基本上是 H5 这边是每次都会用到的。

但是就说一点小的设计,我们对于会场页面是设计了一个 **URL + package **方式,我们会在信鸽,就是我们一个后台去输入需要进行离线的页面,在会场这种场景下。我们信鸽就会在后台跑一个 puppetter,把页面的资源给获取到,并且再通过一些滚屏的操作,把一些懒加载的资源也给获取到。就把整个资源打成一个资源包,最后通过一个hash的方式,在去真实页面访问的时候,进行匹配。

第二点,数据并行请求的这样一个部分,我们设计了相对于正常的 Memory 命中Miss 不命中这样一个状态下,我们还设计了一个 Ongoing 这样一个状态。我们认为只要客户端发起请求,那一定是比前端真实发起请求要快的要提前的,因为实际它肯定是要提前的,所以我们就会等待就是客户端真实的请求返回之后,我们再会拿客户端的那样一个数据,而不是重新发起一次请求。

总结和规划

整个这边就不那么细说了,反正最终达成了我们当时这样一个目标,基于我们之前说到的无论是通用手段也好,还是一些增进手段也好。通用手段可能也是提供了很大的一个帮助,增进手段在它的基础上有个更高的一个提升。反正最终是达成这样一个目标,并且有了这些东西之后,我们会有一些未来可期的这样一种感觉。

总结

C18-7 太吾-如何在双11大促中实现会场页面秒开.020.jpeg

性能优化,慢慢的就会发现它从前端的这样一个职能慢慢的上升到多职能协同的这样一种方式。慢慢你如果去优化,你肯定就慢慢不能站在前端的这样一个视角,慢慢的就会依赖于就类似前面说的 NSR 还有服务端这种 SSR 以及我们现在还有那种 ESR 就是 CDN 边缘计算这样去的一些就是东西,就慢慢你会发现性能优化慢慢是超脱了前端这样一个单纯的职能这样一个方面,你要站在多智能协同方式进行性能优化的尝试。

规划

规划就不那么细说提几点:

  • SSR 同步的方案。我们之前刚才说异步在接口中返回 HTML 的方式,异步的方案。同步的方案就是主文档的那种方式,异步的方案在端内效果是肯定很好的,因为它直接离线包之后,通过数据的 prefetch 并行请求之后直接拿到 HTML,直接渲染到屏幕上去,这样肯定是效果很好的。但是在端外,我们会有很多,比如类似支付宝、手淘这种场景它就用不了端内的一些离线包和 prefetch 这种方式,所以我们还是需要进行一些直接主文档返回的方式;
  • 页面的 Abtest;
  • 客户端那边,要考量接入一下 NativeTab 这样切换多 Tab 的方式;
  • 唤端情况下的一些性能优化,这么多新的优化点,肯定需要统一的状态管理。

这样等等一系列的内功提升,以及我们飞猪这边目标是前端的两秒达标率要达到 90%。所以单纯的单业务,我们端内的单业务当然就需要去拓展到多业务。我们就想法是有一个优化手段及现在在集团内我们是有跨端性能小组是有白皮书这样一个方式,去记录一些优化手段,慢慢去 push 各个业务,进行落地,并且去收集各个业务的一些好的优化的手段,来进行沉淀反哺,慢慢去把整体的性能给提高起来。

C18-7 太吾-如何在双11大促中实现会场页面秒开.021.jpeg

推荐一本书

C18-7 太吾-如何在双11大促中实现会场页面秒开.022.jpeg

最后惯例推荐一本书,这边推荐的就是《金字塔原理》,它是讲一个类似写 PPT 或者是思考表达和解决方式的这样一种逻辑。写 PPT、写文章之类的这样一种逻辑,是一套就是逻辑清晰、重点突出、层次分明,简单易懂的思考表达方式和规范动作。这本书我觉得是挺好的。看了之后对于做 PPT 或者是写文章,都是由不少的帮助的。大家有兴趣的可以去看一下。

团队宣传

最后惯例中的惯例,肯定是需要招人的。我们团队关于是飞猪的用户前端和数字化经营团队,我们的业务是关于旅游的一切我们都可以去尝试。我们团队的基础事项。之前有我们团队的南路,也来分享过 Web Flutter 这样一个方案,我们团队的有 Flutter,那么以及在我们现在 SSR 也是我们团队基于 Serverless 这样一个大潮去做的。还有一些中后台的微前端,以及一体化的开发以及端线互动,以及智能搭建这样一个东西,我们团队技术思想都是包括的。 所以基本上各个方面大家都有包括,所以大家有兴趣就等你了,就可以通过邮箱,P6、P7 多多益善。

大家也可以关注一下我们飞猪技术的公众号,Fliggy F2E 以及掘金,有些之前看到我这篇文章有在掘金上发,也是被我们飞猪前端这边专栏去收藏。如果对跨端这边性能这边有想法的,也可以加我微信了解一下。


关注前端早早聊,跟进学习更多 BFF/GraphQL,请关注第三十届|前端早早聊大会 BFF 专场 - 玩转前后端接口(GraphQL、统一网关、API 接入、API 管理、协议转换、统一安全切面、高并发处理、可视化编排、统一稳定性建设...)8-14 全天直播,9 位讲师,报名上车看直播👉 ):