🚀面试时被问过首屏性能优化吗?我们都能做些啥?

1,111 阅读7分钟

前言

哈喽大家好!我是 嘟老板,在外漂泊多年,终是打算回老家找个工作安定下来,最近在各种做面试准备,顺便整理一波分享分享,希望能对大家有所帮助。今天要聊的主题是 首屏性能优化

阅读本文您将收获:

  1. 首屏性能相关指标及统计方式介绍。
  2. 造成首屏加载缓慢的核心因素。
  3. 具体的优化措施。
  4. 等等...

性能指标

介绍

如何衡量首屏性能是否需要优化,不能单凭个人感觉下定论,用数据说话是最好的方式,性能指标 就是以数据的方式,为我们直观的展示首屏加载情况。

核心性能指标如下:

  • FP(First Paint):首次渲染,在白屏结束时触发,当浏览器开始绘制内容,无论是什么内容,这个时间点就是 FP。
  • FCP(First Contentful Paint):首次内容绘制,浏览器首次绘制来自 DOM 的内容,包括但不限于文本,图片,SVG,canvas等。
  • FMP(First Meaningful Paint):首次渲染有意义的内容,没有固定的计算方法,不同公司的算法也可能不同。
  • LCP(Largest Contentful Paint):最大内容绘制,没有固定的计算方法,不同公司的算法也可能不同。
  • (了解)TBT(Total Blocking Time):总阻塞时间。
  • (了解)TTI(Time To Interact):可交互时间。

放一张网图,帮助大家理解下各个指标所处的阶段:

image.png

在 FP 和 FCP 的解释中,涉及到两个名词:白屏和首屏,那什么是白屏和首屏呢?
白屏时间 = 地址栏输入网址后回车 - 浏览器出现第一个元素
首屏时间 = 地址栏输入网址后回车 - 浏览器第一屏渲染完成

统计

  • FP/FCP:通过浏览器提供的 Performance API 计算。

打开浏览器控制台,输入 performance.getEntriesByType('paint') 回车执行,可以发现打印了一个数组结构:

image.png

其中,name 为 first-paint,即 FP,对应的 startTime 即 FP 消耗的时间;name 为 first-contentful-paint,即 FCP,对应的 startTime 即 FCP 消耗的时间。

  • FMP/LCP:没有标准的统计算法,通常可借助 MutationObserver 手动实现。

影响性能的主要因素

影响首屏加载性能的因素主要分为以下两种:

  • 网络延迟
  • 资源太大

具体改进措施

针对网络延迟

针对网络延迟的优化,主要是一系列预处理操作,如 dns-prefetchpreconnectprefetchprerenderpreload 等。

挑几个说说:

  • cdn,请求接近节点。

  • 预加载 preload,在不执行资源的前提下,预先获取资源。

    为需要预加载的资源标签添加值为 preload 的 rel 属性,如:

    <link rel="preload" href="style.css" as="style" />
    
  • 预渲染 prerender,让浏览器在后台进程渲染特定页面。

    • 资源标签的 rel 属性支持 prerender 值,但是目前已经废弃,且不建议使用。 image.png

    • 使用 prerender 工具,借助无头浏览器 puppeteer 预渲染指定页面,并通过服务端返回。

针对资源太大

针对资源太大的优化,核心是找到资源尺寸和请求数的平衡,合理借助缓存加速资源获取。当然了,终极方式必然是 SSR,然而不是所有项目都能推翻,用 SSR 重构的。

介绍几种常用方式:

  • 分包 小即是快,将一个大的编译文件分成多个小的文件资源,提升获取速度。若使用 ebpack 构建,可使用 SplitChunksPlugin 插件;若使用 Vite 构建,可在 rollupOptions 下配置分块。

  • 按需加载 仅在需要时加载对应的组员,如 Vue Router 路由配置的 component 设为 () => import(@/views/**/*.vue),实现路由懒加载。

  • 缓存 资源缓存是十分有效且高效的优化方式,避免重复请求服务资源,直接在本地内存缓存或硬盘中获取。

    缓存大致分为以下几类:

    • 强缓存
      • (建议)Cache-Control 可设为以下值:

        • (常用)max-age:表示强缓存的最大时间,单位 秒(s),如 max-age=300,表示请求正确返回时间的5分钟内再次加载,会命中强缓存。
        • no-cache:不使用本地缓存,可使用协商缓存。
        • no-store:直接禁止浏览器缓存数据,不能使用任何缓存。
        • public:可被所有用户缓存,包括终端用户和 CDN 等中间代理服务器。
        • private:只能被终端用户浏览器缓存,不允许 CDN 等中间代理服务器对其缓存。
      • Expires:响应头(response header)设置的过期时间,浏览器再次加载资源时,若仍在过期时间内,会命中强缓存。

    • 协商缓存
      • Last-Modify/If-Modify-Since

        浏览器首次请求某个资源时,服务器返回的响应头中会加上 Last-Modify,标识该资源的最后修改时间;当浏览器再次请求该资源时,请求头中会加上 If-Modify-Since,值为之前服务端返回的 Last-Modify。服务器收到请求后发现有 If-Modify-Since,根据资源的最后修改时间判断是否命中缓存。

      • (建议)Etag/If-None-Match 浏览器首次请求某个资源时,服务器响应头中会加上 Etag,值为当前资源在服务器的唯一标识。浏览器再次请求该资源时,请求头会加上 If-None-Match,值为之前服务端返回的 Etag。服务器收到请求后发现有 If-None-Match,则与被请求资源的相应校验串进行比对,判断是否命中协商缓存;

    • 策略缓存,借助 ServiceWorker 实现。
  • 优化图片:推荐 WebP 类型,对于需要用户上传图片的功能,如头像,显示上传大小。

  • 延迟加载,或滚动加载,只渲染可视区域内的内容。

  • tree-shaking,主流构建工具已内置,无需手动处理,需要注意编码方式,仅使用 esm 时才能正常 tree-shaking。

  • 字体压缩,font-spider 按需压缩。

  • 服务端渲染 SSR

  • 局部 SSR,仅特定页面使用服务端渲染,如活动页。

  • PWA,离线缓存。

工具

汇总下文中提及的工具,没准有用。

结语

本文重点介绍了 首屏加载性能优化,包括性能衡量指标,造成性能问题的主要因素及具体的优化措施,旨在帮助同学们加深对于首屏加载优化方式方法的了解和实操思路。希望对您有所帮助!

如您对文章内容有任何疑问或想深入讨论,欢迎评论区留下您的问题和见解。

技术简而不凡,创新生生不息。我是 嘟老板,咱们下期再会。


往期干货