图片的懒加载和预加载

55 阅读2分钟

懒加载

为什么需要懒加载?

浏览器回流重绘完毕页面,指的是html,css加载完毕,但是图片需要发起新的网络请求,当页面图片过多或过大,会导致页面加载缓慢,影响用户体验.

如何实现懒加载

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        img {
            height: 300px;
            display: block;
        }
    </style>
</head>

<body>
    <img src="" data-src="https://t7.baidu.com/it/u=1732966997,2981886582&fm=193&f=GIF" alt="">
    <img src="" data-src="https://t7.baidu.com/it/u=1785207335,3397162108&fm=193&f=GIF" alt="">
    <img src="" data-src="https://t7.baidu.com/it/u=2581522032,2615939966&fm=193&f=GIF" alt="">
    <img src="" data-src="https://t7.baidu.com/it/u=245883932,1750720125&fm=193&f=GIF" alt="">
    <img src="" data-src="https://t7.baidu.com/it/u=3423293041,3900166648&fm=193&f=GIF" alt="">
    <img src="" data-src="https://t7.baidu.com/it/u=3241434606,2550606435&fm=193&f=GIF" alt="">
    <img src="" data-src="https://t7.baidu.com/it/u=1417505637,1247476664&fm=193&f=GIF" alt="">
    <img src="" data-src="https://t7.baidu.com/it/u=3659156856,3928250034&fm=193&f=GIF" alt="">
    <img src="" data-src="https://t7.baidu.com/it/u=1416385889,2308474651&fm=193&f=GIF" alt="">
    <img src="" data-src="https://t7.baidu.com/it/u=2469680087,3014121106&fm=193&f=GIF" alt="">
</body>

<script>
    let height = window.innerHeight; //可视区域高度
    //判断默认情况下应该展示哪些图片
    function lazyLoad() {
        let imgs = document.querySelectorAll('img[data-src]');
        for (let i = 0; i < imgs.length; i++) {
            let rect = imgs[i].getBoundingClientRect(); //获取图片在可视区域的位置信息
            if (rect.top < height && rect.bottom > 0) {
               
                let newImage = new Image(); //创建一个新的图片对象
                newImage.src = imgs[i].getAttribute('data-src'); //设置新图片的src属性为data-src的值
                newImage.onload = function () { //当新图片加载完成后
                    imgs[i].src = newImage.getAttribute('src'); //将新图片的src属性赋值给原图片的src属性
                }
                imgs[i].removeAttribute('data-src'); //移除图片的data-src属性,避免重复加载同一图片
            }

        }
    }

    lazyLoad()
    window.addEventListener('scroll', lazyLoad)

</script>

</html>

这里我们img标签src不给值,将url放进data-src属性中,img中的src属性一旦给值就会自动发请求.在js中判定哪些图片出现在可视范围中.优先加载出现在可视范围中的图片,将data-src中的值给到src,最后移除data-src属性.在window上绑定滑动事件,不断触发函数.由于img标签上的data-src属性已被删除,所以不会再触发,避免重复加载同一图片.

缺点: 当图片过大时,图片出现在可视区域时,会有一段时间的白屏现象,影响用户体验

预加载

-预加载的原理:

-在加载页面的同时,用第二个线程去加载图片,当图片加载完毕时,将图片的资源交给第一个线程,从而实现图片的预加载

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="pic"></div>

  <script>
    let pic = document.getElementById('pic')
    let arr = [
      "https://t7.baidu.com/it/u=1732966997,2981886582&fm=193&f=GIF",
      "https://t7.baidu.com/it/u=1785207335,3397162108&fm=193&f=GIF",
      "https://t7.baidu.com/it/u=2581522032,2615939966&fm=193&f=GIF",
      "https://t7.baidu.com/it/u=245883932,1750720125&fm=193&f=GIF",
      "https://t7.baidu.com/it/u=3423293041,3900166648&fm=193&f=GIF",
      "https://t7.baidu.com/it/u=3241434606,2550606435&fm=193&f=GIF",
      "https://t7.baidu.com/it/u=1417505637,1247476664&fm=193&f=GIF",
      "https://t7.baidu.com/it/u=3659156856,3928250034&fm=193&f=GIF",
      "https://t7.baidu.com/it/u=1416385889,2308474651&fm=193&f=GIF",
      "https://t7.baidu.com/it/u=2469680087,3014121106&fm=193&f=GIF",
    ]

    // 创建一个新的线程
    const worker = new Worker('./worker.js')
    // 将数据发送给子线程
    worker.postMessage(arr)
    // 接收子线程发送的数据
    worker.onmessage = function (e) {
      console.log(e.data);
      const img = new Image()
      // console.log(window.URL.createObjectURL(e.data));
      img.src = window.URL.createObjectURL(e.data)//需要将子线程传过来的图片文件对象Blob转成URL地址,这里我们使用window.URL.createObjectURL这个api进行转换。
      pic.appendChild(img)
    }
  </script>
</body>

</html>
self.onmessage = function(e) {
    // console.log(e.data);
    // 将数组中的地址资源加载出来
    let arr = e.data;
    for (let i = 0; i < arr.length; i++) {
      let xhr = new XMLHttpRequest();
      xhr.open("get", arr[i], true);
      xhr.responseType = 'blob'  // 文件类型
      xhr.send();
      xhr.onload = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
          // console.log(xhr.response);
          self.postMessage(xhr.response);
        }
  
      }
    }
  }

-缺点:

同一时间加载多张图片,对服务器压力较大