从“等等”到“秒开”再到“直开”,是什么让闲鱼社区相见恨晚?

简介: 快让我叉会儿腰~

作者:闲鱼技术-颂晨

背景


闲鱼前端页面的性能常常被人念叨,凡跳转、必跳鱼 的印象深入人心,部分页面甚至需要跳四五下才能打开,最近我们对闲鱼前端页面系统性的做了些优化,由于闲鱼前端技术栈相对多元,不同栈技术原理各不相同,优化方案也有所差异,本文主要介绍目前闲鱼占比较重的 Weex 页面的优化过程。


闲鱼 Weex 页面多以前端渲染为主,其打开过程与 Web 页面略微相近,大致分为以下几个阶段:
image.png
我们将「从开始加载(navigationStart)到屏幕首次 paint(绘制)像素内容」的这段时间称为 白屏时间(FP),将「从开始加载(navigationStart)到首屏内容全部渲染完成」的这段时间称为 首屏时间(FSP),受限于统计口径,目前 Weex 下的首屏时间是不包含图片下载及后续过程的。

优化前后


我们拿闲鱼的直播频道页和玩家频道页作为参考,通过录屏的方式看下优化前后的对比:


1598408942645-cf5a593c-89ca-4c67-910b-ac97921fae64.gif  1598408917311-ca5b2f53-53ab-43ed-96f1-c3b4d9dd7508.gif


通过录屏分帧的方式我们统计了下这两个频道页在不同系统不同机型下的首屏时长:
image.png
可以看到,优化前 iOS、Android 主流机型上的首屏时间都要超过 2s,低端机甚至要 3-5s,优化后各机型的首屏时间均大幅下降,低端机首屏时长控制到了 2s 内,中高端机近乎直开。


拆解分析


确定优化方案前我们对现有的 Weex 页面做了拆解分析,从结果来看,以下几个因素对首屏时间的影响较大:

  1. Bundle 体积:不仅影响 Bundle 加载时长,同时也影响 Bundle 的解析执行耗时(低端机尤为明显)
  2. 首屏数据请求:页面渲染必须在首屏数据请求返回后,接口耗时直接影响首屏时间
  3. 首屏渲染范围:首屏渲染量直接影响渲染时长(低端机尤为明显)

优化方案

基于上面的分析调研,我们初步把优化方案定为四层:

image.png

按照预期优化效果,Weex 页面的打开过程是这样的:
image.png


体现在上述的四层结构中,主要包含以下几个优化点:


Bundle 离线


具体实现是将 Weex Bundle 以资源包为单位、以 URL 前缀为索引,通过一定的更新策略离线到客户端本地,之前的更新策略主要有
访问后安装、启动安装** 两种,对应的更新时机如下:


image.png




这套机制在容器层有统一的方案支撑,但是包命中率一直不高(25% - 55%),导致最终效果差强人意,分析后发现默认的更新策略(访问后安装)与页面回访率强相关,闲鱼的前端页面大都是频道导购型的页面,回访率天然不高,所以包命中率相对应也不会高。


本次优化主要是对更新策略进行了扩展,增加了 “闲时安装” 的更新策略:会在定时更新期间主动安装,如果安装后未使用,则会在一周之后淘汰;如果一周内使用过,则进入常规的更新淘汰机制(一个月未使用淘汰)。


在 “闲时安装” 的更新策略上线后,包命中率大幅提升(稳定后 90% 左右),页面性能也得到了显著提升:
image.png




不依赖首屏接口渲染的页面甚至可以达到「直开」:
直开 2.gif  直开 1.gif


数据预取


传统的首屏数据请求都是在 Bundle 解析完以后发起的,首屏数据返回后渲染页面,是个典型的串行过程。


本次优化中我们把这个串行的过程并行化了:

  1. 将首屏请求的配置序列化以后作为参数配置到了 URL 上,同时支持一些动态替换的参数(譬如经纬度、城市等参数);
  2. 在 navigationStart 的时候由客户端提取首屏请求配置,然后发起请求,并将结果以特定的 Hash Key(通过首屏配置生成的)作为索引存储到本地;
  3. 在业务层真正发起首屏请求的时候会通过 Hash Key 进行比对,命中后将数据取出来返回给业务层;

时序图如下:

image.png


特殊情况下的时序图:


image.png


具体的技术细节本文不再赘述,数据预取的优化策略上线后,首屏时间也得到了一定程度的提升,如下(iOS 侧由于各优化策略并行上线,没能做到单一变量采集性能数据,暂以 Android 侧为参考):
image.png


Bundle 离线、数据预取 的优化策略上线后,部分页面在中高端机型上逼近「直开」:直开2.1.gif  直开2.2.gif

渐进式首屏


渐进式首屏解决的是「最后一公里」的问题,因为在上了「离线包」和「数据预取」的方案后,我们发现:页面首屏时间一定程度上还是受限于首屏接口请求耗时,该方案就是为了降低用户侧的白屏等待时长,具体从以下三个方面着手:

  1. 以接口请求配置生成的索引对接口数据进行缓存

    • 当用户首次进入时,以骨架屏占位来等待业务数据加载;
    • 当用户非首次进入时,会根据接口请求配置生成的索引在本地缓存中查找缓存数据,并完成首屏渲染,同时并行发送接口请求,待新数据返回后,触发页面更新,完成最终渲染;

image.png

  1. 低端机降级方案

    为了用户体验能够更好,在此我们尝试了低端机降级优化方案。以直播频道为例:

    • 只对首屏 Tab 做缓存数据占位优化
    • 减少了低端机上首屏渲染展示数据量


  1. 图片渲染效果优化

     渐进式首屏带来的一个问题是界面更新时的闪动(特别是图片占大篇幅的时候),为了优化此问题,我们将图片从加载到出现的过程改为了渐显过渡,一定程度上消除了图片闪动的生硬感。
    

2222.gif  1111.gif

image.png

按需渲染


渲染页面作为首屏链路中的一环,不同技术栈、不同设备环境下,在页面首屏时间中也会有不同的占比。类Weex、RN 通过前端脚本映射原生组件的技术方案,渲染路径总结起来是:渲染前端 Virtual DOM -> 映射为 Native 指令 -> 将指令传输到 Native 侧 -> Native 执行指令完成渲染。在前三个步骤上,较重的业务逻辑或不合理的代码通常会带来较长的计算通信耗时,中低端机器上尤为明显。通过按需渲染可以有效解决这一问题。
按需渲染主要思路是通过只渲染首屏可见视图来最小化首屏渲染耗时。本次优化中,主要针对以下几个场景做了按需渲染:

  1. 多 Tab 情况下,对于有性能要求的非首屏 tab 页,做数据预加载、页面懒渲染处理
  2. 对带/不带回收机制的长列表做首屏只渲染可见条目,剩余懒渲染处理。可减少带回收机制列表的脚本计算、通信耗时,减少不带回收机制列表的全链路渲染耗时。
  3. 自建或使用轻量级组件替换非必要的重量级组件,如: xSlider。

优化上线后,鱼塘广场页中低端机型的首屏性能有了部分数据上的提升:
image.png
低端机上优化前端渲染阶段对比:
ezgif.com-gif-maker.gif  后.gif

Bundle 瘦身

**
Bundle 体积一方面直接影响 Bundle 下载时间,另一方面也会影响 Android 端的渲染性能(耗时随 Bundle 体积增加 1-2ms/KB),我们在 Bundle 体积上的优化方案较为常规,包括:

  1. 通过 Webpack Bundle Analyzer 分析依赖,减少同 npm 包不同版本依赖
  2. 抽象公共模块,提高代码复用率
  3. 重构基础工具类库,支持按需加载打包

image.png

总结


闲鱼前端的性能优化暂时告一段落,优化过程中沉淀了较多的通用能力,像 Bundle 离线、数据预取、渐进式首屏等等,这些能力在后续会有更大的发挥空间,一些能力也会变得更加智能,譬如目前的数据预取是在 navigationStart 的时候发起的,这个时机已经比传统的页面加载时的时机提前了许多,但其实还可以更加提前,譬如可以在闲鱼客户端中常驻个 TaskSchedule,专门用来处理数据预取的 Task,同时可以结合用户的访问习惯做智能数据预取。


在前端性能要求越来越高的背景下,传统的 Web 加载流程已无法再满足性能优化的需要,所以出现了各种新兴容器 + 配套能力,所以下一代容器的标准形态应该是什么样的?

相关文章
|
4月前
|
API Python
【闲鱼社区互助】学生求助:如何在空闲时提供帮助而不被牵连?
通过编写Python脚本来帮助预约实验室仪器的过程,包括需求分析、获取仪器ID、生成时间列表、处理登录态(使用cookie)、实现预约步骤以及提供完整的代码实现。同时,文章还探讨了使用gevent协程并发请求的可能性,并总结了在实现过程中遇到的问题和思考。
26 2
|
4月前
|
人工智能 搜索推荐 安全
从零到一:微信机器人开发的实战心得
从零到一:微信机器人开发的实战心得
275 2
|
5月前
|
人工智能 运维
学习若依的好地方,若依社区,好的运维,社区,也可以运营自己的社区,可以用于投放软件产品和海报展示,有空可以研究怎样运行社区,好的标题设计
学习若依的好地方,若依社区,好的运维,社区,也可以运营自己的社区,可以用于投放软件产品和海报展示,有空可以研究怎样运行社区,好的标题设计
|
7月前
|
IDE 小程序 前端开发
【经验分享】支付宝社区高效的提问技巧
【经验分享】支付宝社区高效的提问技巧
74 4
助力中国开源码力榜,社区邀请正式开启!
助力中国开源码力榜,社区邀请正式开启!
100 0
|
存储 算法 搜索推荐
淘宝长辈模式技术实践万字总结
长辈模式就是:字大、简单。 四个字背后代表是近100人的项目组的努力,更是淘宝人的情怀与坚持。今天我们在帮助老年人更好得使用互联网产品,就是在帮助未来的自己。
292 0
淘宝长辈模式技术实践万字总结
在网易工作是一种什么样的体验?
在网易工作是一种什么样的体验?
143 0
在网易工作是一种什么样的体验?
|
小程序
今日头条小程序平台今日发布,头条小程序开放了哪些能力?
今日头条小程序平台今日发布,头条小程序开放了哪些能力?
412 0
今日头条小程序平台今日发布,头条小程序开放了哪些能力?
|
弹性计算 运维 Cloud Native
知识太枯燥?带你趣味学!云开发技术图谱首发上线,开启探索之旅!
开发者社区云开发技术图谱活动首发上线,新任务模式带你解锁图谱学习“新姿势”!赶快邀上你的好友们,一起探索云原生应用开发技术图谱的趣味宇宙吧!参与活动有超高机会赢得小米移动电源一个,礼品限量,先到先得!
知识太枯燥?带你趣味学!云开发技术图谱首发上线,开启探索之旅!
|
安全 NoSQL 程序员
开源代码分析技巧之四——国外技术社区提问
在分析源码的时候,我们或多或少都会遇到过技术瓶颈。如果不突破这个瓶颈,接下来的研究就无法继续进行。并且不止对自己是瓶颈、对团队人员、技术顾问、资深人士都没有很好的解决办法。这时候,不妨试一下给源代码作者团队邮件提问。
134 0