JS图片预加载的三种实现方案详解

作者:纸飞机时间:2026-10-23 18:06:14浏览:264

本文详细解析了JavaScript中实现图片预加载的三种主流方案。首先介绍基于原生Image对象与load事件监听的基础方法;其次讲解利用生成器函数结合Promise实现异步控制的进阶技巧;最后演示如何使用ES6的async/await语法将异步操作转化为同步风格,提升代码可读性。

图片预加载基本概念

预加载的核心概念在于:在用户访问页面时,提前将所需图片加载至本地缓存。当后续需要展示图片时,直接调用缓存资源进行渲染,从而避免等待加载的时间。这种技术广泛应用于图片密集的网页场景(如百度图库、淘宝、京东等电商平台),能显著提升用户的浏览体验。

单张图片预加载实现

针对单张图片的预加载实现,我们需要关注加载过程中的状态变化。


var img=new Image();
    img.addEventListener("load",loadHandler);
    img.src="./img/1.jpg";
    document.body.appendChild(img);
    console.log(img.width);

    function loadHandler(e){
      console.log(img.width);//当前图片的原始宽度
    }

在代码执行过程中,如果在图片尚未加载完成时尝试获取其宽度,返回值为0。只有当图片完全加载完毕并插入DOM树完成渲染后,触发load事件的回调函数,此时才能正确获取到图片的原始宽度。

多张图片预加载方案

当需要预加载多张图片时,必须在本地建立缓存机制。下文将介绍三种用于预加载多张图片的具体实现方案。

方案一:load事件预加载

第一种方案:基于load事件的预加载。

假设需要加载100张图片,图片命名规则为1.jpg至100.jpg(后续示例沿用此命名规则)。


var num=1;
    var list=[];
    loadImage();
    function loadImage(){
      var img=new Image();
      img.addEventListener("load",loadHandler);
      img.src="./img/"+num+".jpg";
    }
    function loadHandler(e){
      list.push(this.cloneNode());//复制当前图片元素
      num++;
      if(num>100){console.log(list);return;}
      this.src="./img/"+num+".jpg"; //修改地址继续后触发load事件
    }

上述代码的逻辑流程如下:

1. 创建一个Image对象实例。

2. 为该图片元素绑定load事件监听器。

3. 图片加载完成后,将当前加载好的图片克隆一份,并推入结果数组中。

4. 更新计数器num;若num的值超过100,则停止执行流程,并输出包含所有图片的数组。

5. 将当前图片的src属性修改为下一个图片的地址。由于src改变会重新触发load事件,因此会再次进入loadHandler函数,如此循环直至所有图片加载完成。

方案二:生成器函数预加载

第二种方案:利用生成器函数实现预加载。


function loadImage(src){
    return new Promise(function(resolve,reject){
      let img=new Image();
      img.onload=function(){ 
        resolve(img);//加载时执行resolve函数
      }
      img.onerror=function(){ 
        reject(src+'这个地址错误');//抛出异常时执行reject函数
      }
      img.src=src;
    })
  }
  function* fn(){
    for(let i=1;i<100;i++){
      yield loadImage("./img/"+i+".jpg");
    }
  }
  let s=fn();
  let value=s.next().value; 
  resume();
  function resume(){
    value.then(img=>{
      console.log(img);//打印加载的图片标签
      value=s.next().value;
      if(value)resume();
    });
  }

上述代码的执行逻辑解析如下:

1. 调用生成器函数,并依次执行loadImage函数。

2. 在Promise对象内部创建图片元素。

3. 判断图片加载状态,若加载成功则执行Promise的resolve回调。

4. 执行resume函数,该函数内部处理Promise处于resolved状态时的逻辑。

5. 反复调用s.next().value,直到所有图片加载完毕。

方案三:Async/Await预加载

第三种方案:基于async/await的图片预加载。


function loadImage(src){
    let p=new Promise(function(resolve,reject){
      let img=new Image();
      img.onload=function(){//加载时执行resolve函数
        resolve(img);
      }
      img.onerror=function(){
        reject(src);
      }
      img.src=src;
    })
    return p;
  }
  async function fn(){
    let arr=[];
    for(let i=3;i<80;i++){
      await loadImage(`./img/${i}-.jpg`).then(img=>{
        arr.push(img);
      });
    }
    return arr;
  }
  fn().then(list=>{
    console.log(list);//打印图片数组
  })

该方法利用了ES6引入的async和await关键字,将异步操作转换为阻塞式的同步代码风格。

具体说明如下:

1. 使用async关键字声明的函数标识为异步函数。

2. 在async函数内部可以使用await关键字,其作用是使异步操作变为同步等待,即阻塞式等待。

3. 只有当await后的异步操作全部完成,代码才会继续向后执行。

4. async函数中的await关键字后必须跟随Promise对象。

5. 执行async函数后,其返回值是一个Promise对象。

以上介绍了三种图片预加载的实现方法,供开发者参考选用。

本文内容旨在帮助读者理解相关技术,希望对学习有所帮助,感谢支持。

作者最新文章