- 前端
【免费下载链接】waitForImages
A jQuery plugin that lets you attach callbacks to useful image loading events.
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();之后插件在三处与它交互:
- 每张图加载完成→
deferred.notifyWith(img.element, eachArguments)(L201)。notify是 Deferred 的"进度通知",对应 Promise API 里的.progress()方法,用来实现"逐张完成"的进度回调。 - 最后一张完成→
deferred.resolveWith(...)(L210)。resolve表示"已解决",触发.done()回调。 - 函数返回值→
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),收集三类图片:
<img>元素的src- CSS 属性里的
url()背景图——用正则/url\(\s*(['"]?)(.*?)\1\s*\)/g从background-image等 5 个属性值中提取(L21-L29),\1反向引用确保引号配对 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行教会我们的三件事
- Deferred 三件套(
notify/resolve/promise)能让同一个功能同时提供回调和 Promise 两种 API,且对外只暴露只读的promise() - 事件命名空间是 jQuery 插件的"安全带",让事件的注册与卸载互不干扰
- 计数 + 双事件(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.
相关推荐
终极JSON解析器揭秘:200行代码实现的极速JSON解析器jsmn完全指南
终极JSON解析器揭秘:200行代码实现的极速JSON解析器jsmn完全指南 jsmn是一款用C语言编写的极简JSON解析器,以其惊人的小巧体积和卓越性能著称。
序列化嵌入式jQuery图片加载waitForImages双模式详解:Callback回调 vs Promise Promise深度对比
jQuery图片加载waitForImages双模式详解:Callback回调 vs Promise Promise深度对比 waitForImages 是一款
前端dnGrep文件比较功能详解:如何快速找出文件差异的终极指南
dnGrep文件比较功能详解:如何快速找出文件差异的终极指南 dnGrep是一款强大的Windows图形化GREP搜索工具,除了强大的文本搜索功能外,它还内置了
桌面应用全文检索开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考