news 2026/10/12 16:45:57

waitForImages源码深度解析:200行jQuery如何实现完整图片加载监控(Deferred与事件命名空间)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
waitForImages源码深度解析:200行jQuery如何实现完整图片加载监控(Deferred与事件命名空间)
  • 前端

【免费下载链接】waitForImages

A jQuery plugin that lets you attach callbacks to useful image loading events.

项目地址:https://gitcode.com/gh_mirrors/wa/waitForImages
点击查看免费下载

waitForImages是一个轻量的 jQuery 插件,核心源码只有 226 行,却为图片加载完成了完整的监控能力:它让开发者在页面上所有图片(含background-image背景图、srcset属性图)加载完成后执行回调,并支持逐张进度通知。本文带你逐段阅读 src/jquery.waitforimages.js,看懂它如何用Deferred 对象和事件命名空间这两个机制,写出简洁而健壮的图片加载监控系统。

一分钟认识 waitForImages:解决什么问题?

网页中的图片是异步加载的。在document ready之后、图片真正加载完成之前,浏览器(尤其是旧版 WebKit)可能还没有算出<img>的真实尺寸,导致提前读取的元素高度、偏移量是错的。

waitForImages 的用法非常直观:

$('selector').waitForImages(function() { // 所有图片加载完成,现在再计算尺寸、执行动画都安全了 $(this).slideUp(); });

它的两大能力:

  • ✅完成回调:所有图片加载结束后触发(成功或失败都算"结束")
  • ✅进度回调:每加载完一张图片就通知一次,附带"已加载数/总数/是否成功"

更多用法示例可参考 README.md。

源码地图:226行如何分层?

打开 src/jquery.waitforimages.js,整个文件可以分成 4 个清晰的区域,这也是一个优秀小型插件的典型组织结构:

区域行号职责
UMD 模块包装L1-L12让插件同时支持浏览器、AMD、CommonJS 环境
配置区L14-L31事件命名空间、srcset能力检测、可监听的 CSS 属性表
自定义选择器L34-L50注册:has-src与:uncached两个伪类选择器
主插件函数L52-L225收集图片 → 挂监听 → 计数 → 触发回调

这种"配置与行为分离"的写法值得新手借鉴:把可变的数据(哪些 CSS 属性可能含图)提到外部,用户就能通过$.waitForImages.hasImageProperties自行扩展,而不用改源码。

UMD 包装:一套代码跑遍三种环境

文件开头的 12 行是标准的 UMD(Universal Module Definition)工厂模式:

;(function (factory) { if (typeof define === 'function' && define.amd) { define(['jquery'], factory); // RequireJS / AMD } else if (typeof exports === 'object') { module.exports = factory(require('jquery')); // Node.js / CommonJS } else { factory(jQuery); // 浏览器全局 } }(function ($) { /* 插件主体 */ }));

工厂函数factory接收jQuery作为依赖,外部只负责"按环境把依赖传进来",内部逻辑完全不关心自己运行在哪里。这正是插件在bower install waitForImages或npm install jquery.waitforimages之后都能直接工作的原因(见 README.md)。

Deferred:Promise 风格 API 的心脏

waitForImages 最值得学习的设计,是它用一个$.Deferred对象同时支撑了"回调 API"和"Promise API"两套接口。

主函数一开头就创建了 Deferred(L56):

var deferred = $.Deferred();

之后插件在三处与它交互:

  1. 每张图加载完成→deferred.notifyWith(img.element, eachArguments)(L201)。notify是 Deferred 的"进度通知",对应 Promise API 里的.progress()方法,用来实现"逐张完成"的进度回调。
  2. 最后一张完成→deferred.resolveWith(...)(L210)。resolve表示"已解决",触发.done()回调。
  3. 函数返回值→return deferred.promise()(L223)。注意返回的是promise()而非deferred本身——这是安全的做法:外部只能"订阅"结果,无法强行调用resolve/reject破坏插件内部状态。

这样,用户既可以写传统的waitForImages(fn),也可以写链式的waitForImages().done(fn).progress(fn),而插件内部只需要一套计数逻辑。对比测试用例可以看到这些 API 都有覆盖(test/jquery.waitforimages_test.js)。

事件命名空间:jQuery 插件必学的"防串扰"技巧

浏览器原生监听load事件时,一个常见的坑是:load是通用事件名,你无法区分"这是 waitForImages 挂的监听器"还是"别的代码挂的",卸载时也可能误删别人的监听器。

jQuery 提供了事件命名空间机制,waitForImages 用得很标准(L14、L186-L190):

var eventNamespace = 'waitForImages'; // ... var events = 'load.' + eventNamespace + ' error.' + eventNamespace; $(image).one(events, function me (event) { /* ... */ });

load.waitForImages中的.waitForImages就是命名空间。它带来三个好处:

  • 🔹精准卸载:$(this).off(events, me)只移除带该命名空间的监听器,不影响其他插件
  • 🔹批量清理:off('.waitForImages')可一次性移除本插件的所有事件
  • 🔹代码可读:命名空间让事件"属于谁"一目了然

还有一个细节:监听器同时绑定了load和error两个事件。因为图片加载只有两种结局——成功或失败——用同一个回调统一处理,再通过event.type == 'load'判断成功与否(L196),把"失败"也计入总数,保证finished回调一定会被触发,不会因一张 404 图片而永远卡住。

配合.one()(只触发一次)+ 手动off()的双重保险(L203-L206):.one()只会在自己触发的那条事件上自动解除,而load和error必然只有一个会触发,另一个会残留,所以作者显式地把两个都off掉,避免监听器泄漏。

自定义伪类选择器::has-src 与 :uncached

源码还向 jQuery 注册了两个自定义伪类(L34-L50):

  • img:has-src—— 选中拥有有效非空src的<img>,过滤掉占位符空图
  • img:uncached—— 选中尚未被浏览器缓存的图片(利用原生img.complete属性判断)

实现方式是通过$.expr.pseudos扩展 jQuery 选择器引擎:

$.expr.pseudos.uncached = function (obj) { if (!$(obj).is(':has-src')) { return false; } return !obj.complete; };

插件内部靠:has-src收集图片,外部用户也能直接复用($('img:uncached')),一码两用。

图片收集:正则 url() 匹配与 srcset 兼容

开启waitForAll: true后,插件会把集合内所有后代元素都遍历一遍(L109-L159),收集三类图片:

  1. <img>元素的src
  2. CSS 属性里的url()背景图——用正则/url\(\s*(['"]?)(.*?)\1\s*\)/g从background-image等 5 个属性值中提取(L21-L29),\1反向引用确保引号配对
  3. srcset属性——先通过new Image()探测浏览器是否支持srcset(L16-L19),支持的浏览器会复制srcset/sizes到临时Image上(L216-L219),保证响应式图片同样被监控

参数解析同样贴心(L72-L97):支持"选项对象"和"多参数"两种调用签名,回调缺省时回退$.noop,非函数参数则抛出TypeError快速失败。

边界处理:空列表与完成判定

两个容易忽略的健壮性细节:

  • 找不到图片:allImgsLength === 0时立即调用finishedCallback并resolve(L176-L179),否则"没有图片"的容器会永远等不到回调
  • 完成判定:每张图片的回调里先自增allImgsLoaded,再比较allImgsLoaded == allImgsLength,相等才触发完成(L198-L212);return false则直接终止当前遍历

小结:这200行教会我们的三件事

  1. Deferred 三件套(notify/resolve/promise)能让同一个功能同时提供回调和 Promise 两种 API,且对外只暴露只读的promise()
  2. 事件命名空间是 jQuery 插件的"安全带",让事件的注册与卸载互不干扰
  3. 计数 + 双事件(load/error)+ 空列表短路,是异步批量任务中保证回调"必达"的经典模式

想继续深入,建议按顺序阅读:主源码 src/jquery.waitforimages.js、完整用法 README.md、测试用例 test/jquery.waitforimages_test.js 与构建配置 Gruntfile.js,再看 test/waitforimages.html 了解本地运行测试页面的方式。

  • 前端

【免费下载链接】waitForImages

A jQuery plugin that lets you attach callbacks to useful image loading events.

项目地址:https://gitcode.com/gh_mirrors/wa/waitForImages
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/12 16:44:23

网络切片仿真资源包实战:从资源分配翻车到半静态预留优化

简介&#xff1a;网络切片仿真.rar 面向5G通信网络方向的研究生、科研人员与网络工程师&#xff0c;聚焦共享物理基础设施上多虚拟网络的定制化建模与性能评估。资源围绕网络切片概念、NFV与SDN虚拟化技术、SLA服务等级协议、资源分配、安全隔离、动态调整与自愈能力等核心知识…

作者头像 李华
网站建设 2026/10/12 16:44:02

代码评审实战指南:从流程设计到团队协作的完整落地

1. 从“代码评审”这件事说起“open-code-review”这个标题&#xff0c;乍一看像是一个开源项目的名字&#xff0c;实际上它指向的是一类非常具体的工作场景&#xff1a;把代码评审&#xff08;Code Review&#xff09;这件事&#xff0c;从“靠人盯”变成“有章法、可复用、能…

作者头像 李华
网站建设 2026/10/12 16:31:55

构建可审计的Repository下载治理体系:Git/Maven/NPM全链路实践

简介&#xff1a;本资源是一份面向Java开发者与Git初学者的实战型代码仓库管理学习包&#xff0c;聚焦版本控制核心实践&#xff0c;解决日常开发中远程仓库克隆、依赖管理及项目结构理解等关键问题。压缩包共2000个文件&#xff0c;主体为1506个repositories目录结构、893个ja…

作者头像 李华
网站建设 2026/10/12 16:28:21

工业信号频谱图实战指南:从FFT到故障诊断的四步预处理链

简介&#xff1a;本资源是《傅里叶变换频谱图你必须知道的》视频配套的实践代码与示例数据包&#xff0c;面向信号处理初学者、音视频开发入门者及MATLAB基础学习者&#xff0c;聚焦于理解傅里叶变换原理与频谱图可视化这一核心难点。压缩包含2个关键文件&#xff1a;MATLAB脚本…

作者头像 李华