Fork me on GitHub
随笔 - 87  文章 - 0  评论 - 308  阅读 - 42万

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;
    }
}
复制代码

 

我的重点在于方便理解原理,关于源代码的分析,参看司图正美的博文。此处不在复述。

posted on   bjtqti  阅读(481)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示