有些时候,我们需要等待上一个操作完成之后,才能进行下一步的操作。比如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. STM32之PWM君

    PWM..英语好的人估计又知道这三个大写字母代表哪三个英语单词了.小弟不才,就说中文意思好了:脉冲宽度调制,玩过飞思卡尔的人估计对PWM非常的不陌生吧.电机驱动需要PWM,控制舵机的转向需要PWM,总 ...

  2. CSS3动画快速实现

    在工作或者平时做demo中,经常会遇到做一些简单的动画.初级前端同学可能就会有些棘手了. 在这里我发现了一个网上笔记实用且简单易上手的动画库.与大家共享一下: 更多请查看:http://anicoll ...

  3. adb devices出现no permissions

    在做Android开发的时候,有些设备插入USB调试线,无法调试,出现以下错误: joey 09:58 $ adb devices List of devices attached 20080411 ...

  4. 异步网络加载开源框架AsyncHttpClient使用

    AsyncHttpClient是异步的,但是有时候我们需要得到请求的结果集来返回给某个函数,由于是异步的,所以不能够直接return会去,所以可以定义一个interface来给调用AsyncHttpC ...

  5. 学习笔记:java并发编程学习之初识Concurrent

    一.初识Concurrent 第一次看见concurrent的使用是在同事写的一个抽取系统代码里,当时这部分代码没有完成,有许多的问题,另一个同事接手了这部分代码的功能开发,由于他没有多线程开发的经验 ...

  6. 如何识别一个字符串是否Json格式

    前言: 距离上一篇文章,又过去一个多月了,近些时间,工作依旧很忙碌,除了管理方面的事,代码方面主要折腾三个事: 1:开发框架(一整套基于配置型的开发体系框架) 2:CYQ.Data 数据层框架(持续的 ...

  7. SQL SERVER全面优化-------索引有多重要?

    想了好久索引的重要性应该怎么写?讲原理结构?我估计大部分人不愿意看,也不愿意花那么多时间仔细研究.光写应用?感觉不明白原理一样不会用.举例说明?情况太多也写不全....到底该怎么写呢? 随便写吧,想到 ...

  8. Python黑帽编程2.2 数值类型

    Python黑帽编程2.2  数值类型 数值类型,说白了就是处理各种各样的数字,Python中的数值类型包括整型.长整型.布尔.双精度浮点.十进制浮点和复数,这些类型在很多方面与传统的C类型有很大的区 ...

  9. .Net组件程序设计之远程调用(一)

    .Net组件程序设计之远程调用(一) 1应用程序域 我们知道我们写的C#代码是在操作系统逻辑体系结构中最上层的,然而操作系统本身是不会认识C#代码的,它只认识机器代码.那我们写的程序经过编译后是编译成 ...

  10. 一次Mysql 死锁事故

    故障描述: 简单描述一下需求:我们写的一个计步器的客户端软件,用户通过手机客户端将用户的运动计步信息传到服务器. 服务器侧记录每个用户每次上传明细,同时每个用户有一个汇总值,参与全省排名. 1.加入明 ...