前端性能优化系列——优化白屏时间(一)⚡

一、前言

前端优化是一个永恒的话题,每个前端开发者都希望自己的页面能够快速加载,给用户良好的体验,但是在实际开发中,我们经常会遇到一个棘手的问题,那就是首页白屏问题。

首页白屏问题是指用户打开页面后,需要等待很长时间才能看到页面内容,这会让用户感到不耐烦,甚至流失,造成白屏的原因有很多,比如网络延迟、JS 加载过多、渲染性能不佳等等,针对不同的原因,我们需要采取不同的优化策略。

今天和大家讨论一种常见的场景,以及其中的一种优化手段,这种优化手段可能很多人都不知道,但是它非常有效,可以大幅度提升用户的感知效率。

二、场景回顾

js 复制代码
<template>
  <div class="container">
    <div v-for="n in 100">
      <heavy-comp></heavy-comp>
    </div>
  </div>
</template>

<script setup>
  import HeavyComp from './components/HeavyComp.vue';
</script>

这里我们导入了一个叫做 HeavyComp 的组件,这个组件里有很多很多的元素,特别是在大屏项目里元素可能特别密集,然后我们将这个组件循环了 100 次,每一次循环渲染一次,我们来看一下它的运行效果。

我们会发现有长时间的等待,最后一起把这些组件渲染出来,然后我们使用浏览器的调试工具 Performance 做一下性能分析:

可以看出 2686 毫秒在加载 JS,2795 毫秒在渲染,这样的页面对于用户而言是完全无法接受的,那么怎么来优化呢?

三、如何优化

其实主要的思路就是让这些组件一部分一部分的渲染,一起渲染压力太大,要分摊一下,先渲染其中一部分,让用户能够看到,然后再持续的渲染剩下的部分。虽然总的时间没有变化,甚至还有可能会增加,但是对于用户的感知而言,从用户打开页面到看到东西这段时间被大幅度的缩减了。这里我们先直接使用写好的优化方法:

js 复制代码
<template>
  <div class="container">
    <div v-for="n in 100">
      <!-- 在渲染组件的时候,我们可以利用 defer 函数来进行 if 判断 -->
      <heavy-comp v-if="defer(n)"></heavy-comp>
    </div>
  </div>
</template>

<script setup>
import HeavyComp from './components/HeavyComp.vue';
// 导入一个我已经写好的函数
import { useDefer } from './useDefer';
// 这个函数返回一个方法
const defer = useDefer();
</script>

那么这个 defer 函数有什么作用呢?关于渲染帧大家应该都知道,就是在一个渲染时间线内,它是分成很多小段,每一段都是一个渲染帧,每一个渲染帧的间隔是 16.6 毫秒。

假如说第一个渲染帧叫第一次渲染,第二个渲染帧叫第二次渲染,依次类推,那么这个 defer(n) 表达的意思就是,目前渲染帧有没有超过这个 n

举个例子:比如说 defer(10),传入 10,表达的意思是当渲染的帧数是第一帧的时候,返回 false,第二帧的时候还是返回 false,只有当渲染帧大于等于第十帧的时候才返回 true,就这么简单。

当它返回 false 的时候,由于我们使用了 v-if,那么这个组件它就不会渲染,换句话说,这里给它传一个 n,就表示它循环了 100 次,第一个组件的时候 n 是 1,就表示第一帧的时候渲染第一个组件,第二个组件的时候 n 是 2,就表示第二帧的时候渲染第二个组件,依此类推。

我们来看一下优化后页面的渲染:

我们发现很快就得到了响应,尽管总时间没有变化,因为它还在持续渲染,但是用户感知到它的效率已经大大提升了,我们再次用性能分析工具分析一下。

可以看到,渲染过程被分成了一帧一帧进行渲染,避免了页面长时间的卡顿,每一次渲染用户都能看到它的渲染结果。这有点像 React 的 fiber 架构,在 Vue3 中也有类似的概念,其实都是利用浏览器空闲时间来进行任务调度和拆分。

接下来我们来看看这个函数到底是怎么实现的。

四、useDefer

js 复制代码
import { ref } from "vue";
// 函数接收一个参数,表示监测的最大帧数,这里默认值是 1000
// 如果说你渲染的东西特别多可以传入一个值
export function useDefer(maxFrameCount = 1000) {
  // 然后开始计数
  const frameCount = ref(0);
  const refreshFrameCount = () => {
    requestAnimationFrame(() => {
      // 每一次 requestAnimationFrame 就计数加一
      // 表示当前渲染的帧数变多了一帧
      frameCount.value++;
      // 只要当前帧数小于最大帧数就递归执行
      if (frameCount.value < maxFrameCount) {
        refreshFrameCount();
      }
    });
  };
  refreshFrameCount();
  // 返回一个函数,接收传递进来的 n
  return function (showInFrameCount) {
    // 判断当前渲染的帧数有没有大于 n
    return frameCount.value >= showInFrameCount;
  };
}

五、总结

前端优化之白屏问题是一个非常重要而又常见的问题,我们需要根据不同场景采取不同策略。本文介绍了其中一种场景和优化方法,即利用 defer 函数来控制组件何时进行渲染,让页面内容逐步展现出来,而提高用户感知效率和体验。当然还有其他优化方法和技巧,比如使用骨架屏、预加载、懒加载、代码分割。

本文参考该篇文章,以及渡一教育袁老师的短视频讲解分享。

相关推荐
FungLeo19 分钟前
node 后端和浏览器前端,有关 RSA 非对称加密的完整实践, 前后端匹配的代码演示
前端·非对称加密·rsa 加密·node 后端
不灭锦鲤29 分钟前
xss-labs靶场第11-14关基础详解
前端·xss
不是吧这都有重名1 小时前
利用systemd启动部署在服务器上的web应用
运维·服务器·前端
霸王蟹1 小时前
React中巧妙使用异步组件Suspense优化页面性能。
前端·笔记·学习·react.js·前端框架
Maỿbe1 小时前
利用html制作简历网页和求职信息网页
前端·html
森叶1 小时前
Electron 主进程中使用Worker来创建不同间隔的定时器实现过程
前端·javascript·electron
霸王蟹2 小时前
React 19 中的useRef得到了进一步加强。
前端·javascript·笔记·学习·react.js·ts
霸王蟹2 小时前
React 19版本refs也支持清理函数了。
前端·javascript·笔记·react.js·前端框架·ts
川石课堂软件测试2 小时前
涨薪技术|0到1学会性能测试第65课-SQL捕获阻塞事件
数据库·sql·功能测试·oracle·性能优化·单元测试·tomcat
繁依Fanyi2 小时前
ColorAid —— 一个面向设计师的色盲模拟工具开发记
开发语言·前端·vue.js·编辑器·codebuddy首席试玩官