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

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

  1. /**
  2. * @fileOverview JSDeferred
  3. * @author cho45@lowreal.net
  4. * @version 0.4.0
  5. * @license
  6. * JSDeferred Copyright (c) 2007 cho45 ( www.lowreal.net )
  7. *
  8. * 针对deferred的原理进行精简
  9. */ ; // no warnings for uglify
  10.  
  11. function Deferred () {
  12. return this.init();
  13. }
  14. //定义静态方法
  15. Deferred.ok = function(x) {return x} //缺省的成功回调
  16. Deferred.ng = function(x) {throw x}
  17. //判断是否为Deferred的实例
  18. Deferred.isDeferred = function (obj) {
  19. return !!(obj && obj._id === Deferred.prototype._id);
  20. };
  21.  
  22. //这个next是挂在Deferred上的静态方法。与实列方法.next是不同的
  23. Deferred.next = function(fn){
  24. var d = new Deferred();
  25. var img = new Image();
  26. var handler = function(){
  27. d.canceller();
  28. d.calls();
  29. }
  30. //这个地方个人认为比较巧秒,它利用了img加载成功或错误回调具有异步的特性。
  31. //保证完整收集这些.next().next()...
  32. //事实上官方还用了其它两种方式,确保兼容,如setTimeout....
  33. img.addEventListener('error',handler,false);
  34. d.canceller = function(){
  35. img.removeEventListener('error',handler,false);
  36. }
  37. //这里用来触发一个img的加载事件
  38. img.src = "data:image/png," + Math.random();
  39. if(fn) d.callback.ok = fn;
  40. return d;
  41. }
  42.  
  43. //这里是用来模拟一个比较耗时的异步过程
  44. //实践中,可能是取数据的过程,如等待ajax回调
  45. Deferred.wait = function (n) {
  46. var d = new Deferred(), t = new Date();
  47. var id = setTimeout(function () {
  48. d.calls((new Date()).getTime() - t.getTime());
  49. }, n * 1000);
  50. d.canceller = function () { clearTimeout(id) };
  51. return d;
  52. };
  53.  
  54. Deferred.prototype = {
  55. _id : 8888, //随便填写,用来判断是否为Deferred的实例
  56. init : function(){
  57. this._next = null;
  58. //使Deferred.isDeferred 判断为假
  59. this.callback = {
  60. ok : Deferred.ok,
  61. ng : Deferred.ng
  62. }
  63. return this;
  64. },
  65. next : function (fun) { return this._post("ok", fun) },
  66.  
  67. calls : function (val) { return this._fire("ok", val) },
  68.  
  69. _post : function (okng, fun) {
  70. //个人认为,理解这里是关键,
  71. //._next保存一下实例对象,形成一个链
  72. this._next = new Deferred();
  73. this._next.callback[okng] = fun;
  74. return this._next;
  75. },
  76.  
  77. _fire : function (okng, value) {
  78. var next = "ok";
  79.  
  80. value = this.callback[okng](value);
  81. //这里的value如果不是Deferred的实例
  82. if (Deferred.isDeferred(value)) {
  83. //加载下一个任务
  84. value._next = this._next;
  85. } else {
  86. //说明没有下一个任务了
  87. if (this._next) this._next._fire(next, value);
  88. }
  89. return this;
  90. }
  91. }

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

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

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

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

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

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

  1. function(next1,next2,next3,...){
  2. //....
  3. //....
  4. next1(function(){
  5. next2(function(){
  6. next3(...);
  7. })
  8. })
  9. }

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

  1. Deferred.next(function(){
  2. next1();
  3. }).next(function(){
  4. next2();
  5. }).next(function(){
  6. next3()
  7. }).next(function(){
  8. //...
  9. })

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

如果你觉得怎么写无所谓,那么要结合起来看了,如果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. Log4j按级别输出到不同文件

    log4j.properties 文件: log4j.logger.net.sf.hibernate.cache=debug log4j.rootLogger = error,portal_log,s ...

  2. (转)win7 64 安装mysql-python:_mysql.c(42) : fatal error C1083: Cannot open include file: 'config-win.h': No such file or directory

    原文地址:http://www.cnblogs.com/fnng/p/4115607.html 作者:虫师 今天想在在win7 64位环境下使用python 操作mysql 在安装MySQL-pyth ...

  3. 日常关键字:定时关机、该任务映像已损坏或已篡改.(0x80041321)、ChaZD生词同步扇贝

    我在床上用chinanet网络慢得简直令人发指,12B/S.是的你没有看错,这是我最常看到的网速.但是我最近发现电脑联网开出一个WiFi,在床上用手机上网时,网速会一点提升,可达到1KB/S(⊙﹏⊙) ...

  4. Python之路第一课Day8--随堂笔记(socket 承接上节---网络编程)

    本节内容 Socket介绍 Socket参数介绍 基本Socket实例 Socket实现多连接处理 通过Socket实现简单SSH 通过Socket实现文件传送 作业:开发一个支持多用户在线的FTP程 ...

  5. nginx超时重发

    最近一直遇到一个bug: 客户端会二次请求服务端,服务端多次调用remote服务. 特点是,这些请求都是模型切片相关的,耗时很长的请求,往往需要1分钟左右. 开始以为是客户端代码有问题,进行了二次请求 ...

  6. 自写函数VB6 STUFF函数 和 VB.net 2010 STUFF函数 详解

    '*************************************************************************'**模 块 名:自写函数VB6 STUFF函数 和 ...

  7. HTML基础篇之知识点补充和拓展

    <tbody>标签 <tbody>如果表格内容非常多的时候,如果加上这个标签它会让这个表格全部下载好才会显示.用在表格标签上面. 如果您使用 thead.tfoot 以及 tb ...

  8. 下载判断Android和iOS

    //下载 function down(){ var url = ''; var u = navigator.userAgent, app = navigator.appVersion; var isA ...

  9. C# DataSet

    一.基本概念 DataSet是ADO.NET的中心概念.可以把DataSet当成内存中的数据库,DataSet是不依赖于数据库的独立数据集合.所谓独立,就是说,即使断开数据链路,或者关闭数据库,Dat ...

  10. Android图片资源

    title: 2016-5-5未命名文件 tags: UI适配,图片资源 grammar_cjkRuby: true --- 概述: 本文整理了Android开发中,图片资源的提供方式和使用方式.包括 ...