Deffered.js的实现原理
在艾伦的推荐下,看了一个日本人写的延时加载库,非常轻量,写的很棒。作为我的源码学习的第一编。
在认真看了两天之后,才看懂它的实现原理,我下面把通自己的理解,进行了精简。只程现原理,方便日后的回顾。<!DOCTYPE HTML>
<html> <head> <meta charset="utf-8"> <title>deffred</title> <meta name="Keywords" content=""> <meta name="Description" content=""> </head> <body> <script type="text/javascript" src="deffered.js"></script> <script type="text/javascript"> Deferred.next(function(){ alert(1)
//这里直接return ;则会立即调用alert(2),没有异步过程 return Deferred.wait(3) }).next(function(){ alert(2) }) </script> </body> </html>
deffered.js是我精简之后的代码,并加了一些注释:
/** * @fileOverview JSDeferred * @author cho45@lowreal.net * @version 0.4.0 * @license * JSDeferred Copyright (c) 2007 cho45 ( www.lowreal.net ) * * 针对deferred的原理进行精简 */ ; // no warnings for uglify function Deferred () { return this.init(); } //定义静态方法 Deferred.ok = function(x) {return x} //缺省的成功回调 Deferred.ng = function(x) {throw x} //判断是否为Deferred的实例 Deferred.isDeferred = function (obj) { return !!(obj && obj._id === Deferred.prototype._id); }; //这个next是挂在Deferred上的静态方法。与实列方法.next是不同的 Deferred.next = function(fn){ var d = new Deferred(); var img = new Image(); var handler = function(){ d.canceller(); d.calls(); } //这个地方个人认为比较巧秒,它利用了img加载成功或错误回调具有异步的特性。 //保证完整收集这些.next().next()... //事实上官方还用了其它两种方式,确保兼容,如setTimeout.... img.addEventListener('error',handler,false); d.canceller = function(){ img.removeEventListener('error',handler,false); } //这里用来触发一个img的加载事件 img.src = "data:image/png," + Math.random(); if(fn) d.callback.ok = fn; return d; } //这里是用来模拟一个比较耗时的异步过程 //实践中,可能是取数据的过程,如等待ajax回调 Deferred.wait = function (n) { var d = new Deferred(), t = new Date(); var id = setTimeout(function () { d.calls((new Date()).getTime() - t.getTime()); }, n * 1000); d.canceller = function () { clearTimeout(id) }; return d; }; Deferred.prototype = { _id : 8888, //随便填写,用来判断是否为Deferred的实例 init : function(){ this._next = null; //使Deferred.isDeferred 判断为假 this.callback = { ok : Deferred.ok, ng : Deferred.ng } return this; }, next : function (fun) { return this._post("ok", fun) }, calls : function (val) { return this._fire("ok", val) }, _post : function (okng, fun) { //个人认为,理解这里是关键, //._next保存一下实例对象,形成一个链 this._next = new Deferred(); this._next.callback[okng] = fun; return this._next; }, _fire : function (okng, value) { var next = "ok"; value = this.callback[okng](value); //这里的value如果不是Deferred的实例 if (Deferred.isDeferred(value)) { //加载下一个任务 value._next = this._next; } else { //说明没有下一个任务了 if (this._next) this._next._fire(next, value); } return this; } }
我的重点在于方便理解原理,关于源代码的分析,参看司图正美的博文。此处不在复述。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?