有些时候,我们需要等待上一个操作完成之后,才能进行下一步的操作。比如Ajax实现自动提交表单操作的时候,程序需要等待,一旦有返回结果了,则继续进行一下步操作。

这时deferred.js这个库就产生了,当然,jquery也有这个功能。下面就分析一下这个库的原理:

/**
* @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;
}
}

为了配合分析,先给一段测试代码,方便追踪它的流程。

Deferred.next(function(){
alert(1)
return Deferred.wait(3)
}).next(function(){
alert(2)
})

这里用了一个链式写法,熟jquery的人,对此一定不会陌生。首先是调用Deferred.next()这个方法,返回一个Deferred的实例,然后调用实例上的next()方法。

意图是要执行第一个函数(弹出1)之后,再执行第二函数(弹出2),仅管在写法是同步的,但是执行的时候却是异步的。 你或许会问, 为什么不直接用setTimeout呢?

这个问题非常好,其实在很情况下,我觉得确实是可以等价交换。但是setTimeout有一个使用前提,那就是我们必需事先知道上一步运行完成需要等多长时间。而Deferred不需要。

这时你或许又会问,那为什么不用回调呢?这回我终于没有办法说什么了。直接演示一下这种写法:

function(next1,next2,next3,...){
//....
//....
next1(function(){
next2(function(){
next3(...);
})
})
}

像竹笋一样,一层套一层。如果函数体长一点,看着不晕吗?再看看deferred的写法:

Deferred.next(function(){
next1();
}).next(function(){
next2();
}).next(function(){
next3()
}).next(function(){
//...
})

像麻将一样,一字排开,是时髦的链式用法。

如果你觉得怎么写无所谓,那么要结合起来看了,如果next1是一个耗时不确定的操作,但是要保证执行顺序。怎么破?

不管你怎么破,反正我是选择Deferred,用定了。

延时调用--deferred.js原码分析的更多相关文章

  1. basket.js 源码分析

    basket.js 源码分析 一.前言 basket.js 可以用来加载js脚本并且保存到 LocalStorage 上,使我们可以更加精准地控制缓存,即使是在 http 缓存过期之后也可以使用.因此 ...

  2. jqGrid pivot获取所有行包括小计数据及原码分析

    1.结论:按正常jqGid获取,在中间加入以下代码,即将小计行当成改变为普能行,以便能让'getRowData'方法获取到,第三点会进行原码分析 //get all page grid data,in ...

  3. events.js 源码分析

    events.js 源码分析 1. 初始化 // 使用 this.ee = new EventEmitter(); // 源码 // 绑定this域,初始化 _events,_eventsCount和 ...

  4. Require.js 源码分析

    本文将简单介绍下个人对require.js的源码分析,简单分析实现原理 一.require加载资源的流程 require中,根据AMD(Asynchronous Module Definition)的 ...

  5. Backbone.js源码分析(珍藏版)

    源码分析珍藏,方便下次阅读! // Backbone.js 0.9.2 // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. // Backbone ...

  6. Vue.js 源码分析(三十一) 高级应用 keep-alive 组件 详解

    当使用is特性切换不同的组件时,每次都会重新生成组件Vue实例并生成对应的VNode进行渲染,这样是比较花费性能的,而且切换重新显示时数据又会初始化,例如: <!DOCTYPE html> ...

  7. Vue.js 源码分析(三十) 高级应用 函数式组件 详解

    函数式组件比较特殊,也非常的灵活,它可以根据传入该组件的内容动态的渲染成任意想要的节点,在一些比较复杂的高级组件里用到,比如Vue-router里的<router-view>组件就是一个函 ...

  8. Vue.js 源码分析(二十九) 高级应用 transition-group组件 详解

    对于过度动画如果要同时渲染整个列表时,可以使用transition-group组件. transition-group组件的props和transition组件类似,不同点是transition-gr ...

  9. Vue.js 源码分析(二十八) 高级应用 transition组件 详解

    transition组件可以给任何元素和组件添加进入/离开过渡,但只能给单个组件实行过渡效果(多个元素可以用transition-group组件,下一节再讲),调用该内置组件时,可以传入如下特性: n ...

随机推荐

  1. dev winform导出功能

    SaveFileDialog fileDialog = new SaveFileDialog(); fileDialog.Title = "导出Excel"; fileDialog ...

  2. SpringMVC自定义处理器里的那些事

    一.如何让一个普通类成为Controller? ①:实现接口Controller 解析:handleRequest(request,response) ②:继承AbstractController 解 ...

  3. Smart3D系列教程1之《浅谈无人机倾斜摄影建模的原理与方法》

    一.引言 倾斜摄影测量技术是国际测绘遥感领域近年发展起来的一项高新技术,以大范围.高精度.高清晰的方式全面感知复杂场景,通过高效的数据采集设备及专业的数据处理流程生成的数据成果直观反映地物的外观.位置 ...

  4. python Django session/cookie

    一, Cookie #cookie # def cook1(request): # print(request.COOKIES) # 查看cooke # # print(request.get_sig ...

  5. Android Studio编码问题

    Android Studio编码问题 不同于Eclipse,选中项目右击即会出现"Properties"选项,可以设置项目文件的默认编码,可以根据自己的需要设置为UTF-8/GB2 ...

  6. Local Desktop

    Desktop: Paradigm System I:\Apps\Admin\ParaStart.bat Paradigm 1 Report Menu  I:\Apps\Admin\ParaStart ...

  7. windows下C++高精度计时

    写代码时,经常会计算某一段代码的运行时间,以下提供一个微秒级别的类供参考 class CTimeCost { public: CTimeCost(const string &str) : m_ ...

  8. js面向对象基础总结

     js中如何定义一个类? 定义的function就是一个构造方法也就是说是定义了一个类:用这个方法可以new新对象出来. function Person(name, age){ this.name = ...

  9. bzoj 2739 最远点

    Description 给你一个N个点的凸多边形,求离每一个点最远的点. Input 本题有多组数据,第一行一个数T,表示数据组数. 每组数据第一行一个数N,表示凸多边形点的个数,接下来N对数,依次表 ...

  10. java.sql.SQLException: 关闭的连接

    在Dao接口实现类里面的conn.close()之类的关闭数据库连接的代码注释掉就可以了. 可能还有别的解决方法,不过这样改比较方便.