浅析图片懒加载(三种实现方法与两种优化方式)

写在前面

上一篇文章介绍了防抖和节流,那么今天我们就来康康图片懒加载(中间会涉及到节流的优化问题)

你将了解到图片懒加载的实现的三种方法(整体位置比较和视图位置比较和observe)

和优化的两种方式(节流IntersectionObserver)


写得不对的地方,希望大家能够批评指正!

在不使用图片懒加载的情况下,我们打开开发者工具康康

  • 这里displayblock是为了让图片变成块元素,这样图片会自己换行,这样更方便后面进行懒加载的操作
  • 注意勾选禁用缓存,和慢速3G,这样效果更加明显

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    img {
      display: block;
      width: 100px;
      height: 100px;
      margin-top: 20px;
    }
  </style>
</head>

<body>
  <p>今天介绍一下图片懒加载</p>
  <img src="./pic/1.png" alt="">
  <img src="./pic/2.png" alt="">
  <img src="./pic/3.png" alt="">
  <img src="./pic/4.png" alt="">
  <img src="./pic/5.png" alt="">
</body>

</html>

  • 我们很容易看出,由于图片的加载时间很长,首屏的渲染用了7s完成
  • 下面我们就来看看懒加载和懒加载的优化吧!
  • 康康最后通过优化能提升多少性能!

什么是懒加载?

这里就来介绍一下懒加载

  • 简单来说,就是懒惰的加载明日复明日
  • 在首屏渲染,如果我的可视区域里面看不到图片,那就先不加载图片
  • 这种合理的偷懒就是懒加载,它大大缩减了首屏的渲染时间

懒加载的前两种实现方法(位置判断)

  • 获取图片元素,图片的src属性改为data-src,即src属性为空
  <img data-src="./pic/1.png" alt="">
  <img data-src="./pic/2.png" alt="">
  <img data-src="./pic/3.png" alt="">
  <img data-src="./pic/4.png" alt="">
  <img data-src="./pic/5.png" alt="">
  • 添加滚动事件监听,判断图片位置和当前位置来给src赋值,从而达到了动态加载图片的效果
  • 这个距离的判断又有大概两种,下面来分析一下

1.通过整体距离来判断

  • 通过下图,我们可以知道
    • 一个图片元素的位置的顶部可以用offsetTop属性获得
    • 如果把div换成文档对象,scrollTop+clientHeight就可以表示滚动距离的最下端
    • offsetTop<scrollTop+clientHeight的时候我们就要改变图片的src
    • 注意上面的offsetTop和后面的scrollTop+clientHeight是针对不同的元素哦,前者是图片,后者是文档对象
    • document.documentElement会返回一个文档对象
      在这里插入图片描述

  • 故代码如下:
    const images = document.querySelectorAll('img')
    n = 0
    let lazyload = (e) => {
      const clientHeight = document.documentElement.clientHeight
      const scrollTop = document.documentElement.scrollTop
      for (let i = n; i < images.length; i++) {
        if (images[i].offsetTop < clientHeight + scrollTop) {
          images[i].setAttribute('src', images[i].getAttribute('data-src'))
          n = i + 1
        }
      }
      console.log('scroll触发');
    }

2.通过视口距离来判断

  • 与上面的方法不同的是,我们不去管整体滚动了多少,图片相对于整体的offset位置是多少
  • 我们只去关心视口的距离
  • getBoundingClientRect().top可以帮我们获得图片相对于视口距离顶部的距离
  • window.innerHeight可以帮我们获得视口的高度(一般来说,对一个设备来说是一个固定值!)
    const images = document.querySelectorAll('img')
    let n = 0
    let lazyload = (e) => {
      for (let i = n; i < images.length; i++) {
        const imageTop = images[i].getBoundingClientRect().top
        if (imageTop < window.innerHeight) {
          images[i].setAttribute('src', images[i].getAttribute('data-src'))
          n = i + 1
        }
      }
      console.log('scroll触发');
    }

3.两种距离判断方法的比较示意图

为了更好地帮助大家理解这个判断的区别,我画了一个示意图

在这里插入图片描述

为什么要优化懒加载

  • 在前面的懒加载函数中,我们写了一个log
  • 好,现在我们去控制台看一下输出
    在这里插入图片描述

scroll多次监听事件多次触发,这是我们不愿意看到的

懒加载的两种优化方式

  • 懒加载的优化本质上就是减少监听事件的调用

节流

  • 在上一篇文章里面提到了节流,我们直接拿节流函数过来用
    function throttle (fn, delay) {
      let pre = 0
      let timer
      return function () {
        if (!pre) pre = new Date()
        let now = new Date()
        let context = this
        let args = arguments
        let remainTime = delay - (now - pre)
        if (now - pre > delay) {
          fn.apply(context, args)
          pre = now
        } else {
          if (timer) return
          timer = setTimeout(() => {
            fn.apply(context, args)
            pre = now
            timer = null
          }, remainTime)
        }
      }
    }
    window.onscroll = throttle(lazyload, 1000)

  • 我们看控制台可以明显看到调用次数减少了
  • 虽然完成了所有的懒加载后,但是我们仍然可以触发事件,所以才有了第二种优化方式

在这里插入图片描述

IntersectionObserver(第三种实现方法,同时是第二种优化方式)

  • IntersectionObserver是什么?
    • 允许你追踪目标元素与其祖先元素或视窗的交叉状态。此外,尽管只有一部分元素出现在视窗中,哪怕只有一像素,也可以选择触发回调函数。
    • 所以它完美契合了懒加载!
  • 我们从代码中来学习它的用法吧!
   const images = document.querySelectorAll('img')
    const callback = (entries) => {
      entries.forEach(entry => {
        console.log(entry)
        if (entry.isIntersecting) {            // 监听到出现
          const image = entry.target           // 获取目标
          image.setAttribute('src', image.getAttribute('data-src'))
          observer.unobserve(image)            // 取消监听
          console.log('触发');
        }
      })
    }
    const observer = new IntersectionObserver(callback)
    images.forEach(image => {
      observer.observe(image)
    })
  • 函数中log entry,我们主要是康isIntersecting属性来判断是否出现
    在这里插入图片描述

  • 通过这个优化方式,几张图片就会触发几次,不会多次触发!
  • observer会监听交叉状态,即出现和消失,出现交叉状态后会去调用new的时候传入的callback回调函数
    • observer.observe添加交叉监听
    • observer.unobserve取消交叉监听
    • 上面这两个api基本够用了
    • 给每张图片添加observe
    • callback里面判断交叉出现,就给src赋值然后unobserve

最后,我们看一下优化后懒加载能提高多少性能

  • 从第一次渲染加载5张图片变成了加载2张图片
  • 请求的总耗时从7s降到了6s
  • 从我自己实验打开,还是明显感觉到要快一些了的(当然是在3G慢速模式下)
    在这里插入图片描述

总结

  • 1.前两种方法存在多次触发问题,所以我们可以使用节流来优化
  • 2.第三种方法自己就考虑的优化(所以第三种方法也就是第二种优化方式)
  • 3.咋一看,第三种方法是可以取代前两种方法的
    • 但是,有的浏览器不兼容第三种方法的时候,我们就只能老老实实使用前两种方法并节流优化了
  • 17
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在Python中,如果使用matplotlib库绘制图片时,保存速度变得非常慢,有一种有效的办法可以优化保存速度。首先找到你虚拟环境中matplotlib库的pyplot.py文件的位置,一般位于你项目目录的venv\Lib\site-packages\matplotlib\pyplot.py。然后打开这个文件,在savefig函数里找到fig.canvas.draw_idle()这一行,并将其注释掉。这样可以明显提升保存时间,从而优化图片保存速度。 另外,使用matplotlib库绘制图片的方法非常简洁,并且没有依赖于其他库,这使得它非常方便使用。 在处理大量数据时,有时通过Python直接处理文件数据并显示在Matplotlib窗口上的速度会比使用C代码慢很多。为了优化这个问题,可以尝试不同的方法,例如使用其他优化技术或者将部分代码转移到C语言中来处理。这样可以提高在Python中读取和显示视频文件的效率。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python matplotlib保存图片太慢?全网最新解决办法,速度快了一半](https://blog.csdn.net/qq_43495412/article/details/127745876)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Python Matplotlib 绘制表格](https://blog.csdn.net/qq_34666857/article/details/126638577)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [浅析Python 读取图像文件的性能对比](https://download.csdn.net/download/weixin_38593644/14869472)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值