JavaScript图片懒加载与预加载技术解析

作者:闭包旅人

时间:2026-10-30

浏览:321

本文深入解析JavaScript中图片懒加载与预加载两种核心技术的实现原理。懒加载通过延迟或条件触发减少服务器压力,预加载则利用Image对象提前获取资源以提升用户体验。文章详细对比了两者在性能与体验上的权衡,并提供了基于setTimeout、可视区监控及Image.complete属性的具体代码实现方案,涵盖IE6兼容性及图片尺寸预获取技巧。

文章目录

懒加载与预加载概述

本文主要探讨懒加载与预加载两种技术的实现细节,直接切入主题进行解析。

懒加载,亦称为延迟加载:此前文章曾提及,即JS图片延迟加载。其核心逻辑是延迟加载图片或仅在满足特定条件时才加载指定图片。

预加载:指提前加载图片资源,当用户需要查看时,可直接从本地缓存中渲染图像。

两种技术的本质区别在于行为相反:一个是提前加载,另一个则是迟缓甚至不加载。懒加载能在一定程度上缓解前端服务器的压力,而预加载则会增加前端服务器的负载。

懒加载的实现方式

懒加载的意义及其实现方式如下:

意义:懒加载的主要目的是优化服务器前端性能,通过减少请求数量或延迟请求时间来降低负载。

实现方式:

1. 第一种为纯粹的延迟加载,通过setTimeout或setInterval函数实现加载时间的延迟。

2. 第二种为条件加载,当符合特定条件或触发某些事件时,才开始异步下载图片。

3. 第三种为可视区加载,即仅加载用户当前可见区域内的图片。这主要通过监控滚动条来实现,通常会在用户即将看到某张图片前的一定距离开始加载,以确保用户滚动时图片恰好显示。

预加载的实现原理

预加载的意义及其实现方式如下:

预加载可视为牺牲服务器前端性能以换取更佳的用户体验,使用户操作获得最快响应。实现预加载的方法众多,可使用CSS(background)、JS(Image)或HTML(<img />)。常用方法是new Image(),通过设置其src属性来实现预加载,并利用onload方法回调预加载完成事件。只要浏览器将图片下载到本地,相同src的资源便会使用缓存,这是最基本且实用的预加载方法。当Image下载完图片头后,可获得宽高信息,因此可在预加载前获取图片大小(方法是用计时器轮询宽高变化)。

如何实现预加载?

通过搜索引擎查询可见,许多人采用以下方式实现预加载:代码如下:

预加载基础代码实现


 function loadImage(url,callback) {
  var img = new Image();
  
  img.src = url;
  img.onload = function(){
    img.onload = null;
    callback.call(img);
  }
}

为何其他浏览器运行正常?原因很简单,涉及浏览器缓存机制。除IE6外(Opera理论上支持,但经测试未复现,可能是版本差异或已修复),其他浏览器重新点击时会再次执行onload方法,而IE6则直接从浏览器缓存中获取。

如何解决该问题?最佳方案是Image拥有一个状态值以表明是否已成功载入。从缓存加载时,因无需等待,该状态值直接表明已下载;而从HTTP请求加载时,因需等待下载,该值显示为未完成。经搜索发现,存在一个各浏览器兼容的Image属性——complete。因此,在图片onload事件之前先对该值进行判断即可。最终代码如下:

解决IE6缓存兼容性问题


function loadImage(url,callback) {
  var img = new Image();
  
  img.src = url;

  if(img.complete) { // 如果图片已经存在于浏览器缓存,直接调用回调函数
    
    callback.call(img);
    return; // 直接返回,不用再处理onload事件
  }

  img.onload = function(){
    img.onload = null;
    callback.call(img);
  }
}

即如果图片已在浏览器缓存中,则支持直接从浏览器缓存取得并直接执行img.complete中的函数,随后返回。

然而,上述代码需等待图片加载完成后才能执行回调函数,或者说等图片加载后可获取图片宽度和高度。若想提前获取图片尺寸该如何处理?网络经验表明:浏览器在加载图片时,会先占用一块区域然后慢慢加载完毕,且无需预设width与height属性,因为浏览器能获取图片头部数据。基于此,只需使用JavaScript定时侦测图片尺寸状态即可得知图片尺寸就绪状态。代码如下:(注:此方式非本人原创,亦非本人编写代码,仅为知晓此原理)

提前获取图片尺寸方案


var imgReady = (function(){
  var list = [],
    intervalId = null;

  // 用来执行队列
  var queue = function(){

    for(var i = 0; i < list.length; i++){
      list[i].end ? list.splice(i--,1) : list[i]();
    }
    !list.length && stop();
  };
  
  // 停止所有定时器队列
  var stop = function(){
    clearInterval(intervalId);
    intervalId = null;
  }
  return function(url, ready, error) {
    var onready = {}, 
      width, 
      height, 
      newWidth, 
      newHeight,
      img = new Image();
    img.src = url;

    // 如果图片被缓存,则直接返回缓存数据
    if(img.complete) {
      ready.call(img);
      return;
    }
    width = img.width;
    height = img.height;

    // 加载错误后的事件 
    img.onerror = function () {
      error && error.call(img);
      onready.end = true;
      img = img.onload = img.onerror = null;
    };

    // 图片尺寸就绪
    var onready = function() {
      newWidth = img.width;
      newHeight = img.height;
      if (newWidth !== width || newHeight !== height ||
        // 如果图片已经在其他地方加载可使用面积检测
        newWidth * newHeight > 1024
      ) {
        ready.call(img);
        onready.end = true;
      };
    };
    onready();
    // 完全加载完毕的事件
    img.onload = function () {
      // onload在定时器时间差范围内可能比onready快
      // 这里进行检查并保证onready优先执行
      !onready.end && onready();
      // IE gif动画会循环执行onload,置空onload即可
      img = img.onload = img.onerror = null;
    };
    
    
    // 加入队列中定期执行
    if (!onready.end) {
      list.push(onready);
      // 无论何时只允许出现一个定时器,减少浏览器性能损耗
      if (intervalId === null) {
        intervalId = setInterval(queue, 40);
      };
    };
  }
})();

调用方式如下:


imgReady('http://img01.taobaocdn.com/imgextra/i1/397746073/T2BDE8Xb0bXXXXXXXX-397746073.jpg',function(){
  alert('width:' + this.width + 'height:' + this.height);
});

以上就是本文的全部内容,希望本文所述对你有所帮助,希望大家继续关注我们的网站!想要学习jsp可以继续关注本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章