1. 问题点描述
  2. 问题分析
  3. 解决思路
  4. 如何解决判断可见性问题
  5. Intersection observer 的概念和用法
  6. 具体实现
  7. 应用效果
  8. 总结

问题起源于我们的一个页面,下面是这个页面的截图和初次请求的瀑布图。

可以看到 进入页面之后,页面初始加载的时候,一共请求了155个资源,请求的瀑布图就快要和页面一样长了.

根据接口请求,我们可以看到。绝大多数请求的接口都是来自于某个接口,那么这个接口是做什么的呢?

这个接口用于通过我们一开始获取到的图表信息,来拉取对应的图表要展示的数据。

而看页面图来看,当前我只看了三个图表,但却发了所有图表的请求,如果我不往下拖拽页面 只看这三个图表,那么其他的请求就完全处于浪费的情况了。

总结来说,存在一个问题就是:接口请求数据存在不一定的浪费情况。

回到页面上,我们可以看到页面是由多个面板来分割的图表区域,那么首先我们就能想到,能否利用图片懒加载的思路来懒加载元素或数据呢?

实际上,完全可以。

那这样,我们就可以得出,两个主要的解决思路。

  1. 组件化分治思想
    1. 为了方便后续的优化,我们必须要求在每个模块之间降低耦合,将相关的逻辑(比如说接口、请求、相关的依赖资源 封装在内部,在Vue中落实成组件的形式。
  2. 加载优先级
    1. 在完成了组件化的拆分(设计时就是如此),确保模块之间不会互相影响和产生耦合之后,我们可以方便地调整加载策略。加载的策略是根据可见性来处理优先级问题。

从前我们都是通过监听滚动事件、resize 事件来判断模块是否可见,代码不仅繁琐,而且一不小心没有函数去抖就又可能导致严重的性能问题。

现在我们有了更好的选择—— IntersectionObserver API ,IntersectionObserver 允许你配置一个回调函数,每当 target ,元素和设备视口或者其他指定元素发生交集的时候该回调函数将会被执行。

这个 API 的设计是异步的,而且保证你的回调执行次数是非常有限的,而且回调是会在主线程空闲时才执行,在性能方面表现更优,使用起来也更简单。

目前是现代浏览器支持,低版本浏览器可以通过 polyfill 兼容。




// 参数
let options = {
    root: document.querySelector('#scrollArea'),// 指定根(root)元素,用于检查目标的可见性。必须是目标元素的父级元素。如果未指定或者为null,则默认为浏览器视窗.
    threshold: 1.0 // 该值为1.0含义是当target完全出现在root元素中时候 回调才会被执行。 
}
// 回调函数 
let callback =(entries, observer) => {
  entries.forEach(entry => {
    // Each entry describes an intersection change for one observed
    // target element:
    //   entry.boundingClientRect
    //   entry.intersectionRatio
    //   entry.intersectionRect
    //   entry.isIntersecting
    //   entry.rootBounds
    //   entry.target
    //   entry.time
  });
}; 
// 实例
let observer = new IntersectionObserver(callback, options);
// 开始对target的监听 
observer.observe(target); 
// 停止对target监听
observer.unobserve(target);

我们学会了如何利用IntersectionObserver API来判断元素可见性之后,就可以利用它,来判断我们的图表面板是否在浏览器窗口中可见,如果可见那么才发起请求获取图表的数据。

|

this.$nextTick(() => {
      let target = this.$refs['chart-panel'].$el
      let observer = new IntersectionObserver((entries) => {
        // 如果不可见,就返回
        // intersectionRatio 目标元素的可见比例
        // 如果不可见
        if (entries[0].intersectionRatio <= 0) return;
        // 发起请求
        this.getEchartData()
        // 停止对target监听
        observer.unobserve(target);
      });
      observer.observe(target);
    })

我们再来看看开始那个页面的情况,在使用了 懒加载技术后,请求数变成了只有 94个,瀑布图变得比较短了,接口的调用明显变少。

这篇文章分享了从遇到业务实际性能问题,到分析、解决并梳理出通用的解决方案的过程,重点其实不是最终的实现代码实现,而是解决问题的角度和过程。

在字节跳动做在线讲义,如何死磕前端性能优化?

Intersection Observer API

性能优化之组件懒加载: Vue Lazy Component 介绍

最后修改:2023 年 03 月 24 日
如果觉得我的文章对你有用,请随意赞赏