先来看使用案例:

var def1 = $.Deferred();
var def2 = $.Deferred();
var def3 = $.Deferred();
var def4 = $.Deferred(); var fun1 = function (def) {
setTimeout(function () {
console.log("fun1 resolve");
def.resolve();
}, 3000);
return def;
};
var fun2 = function (def) {
setTimeout(function () {
console.log("fun2 resolve");
def.resolve();
}, 2000);
return def;
};
var fun3 = function (def) {
setTimeout(function () {
console.log("fun3 resolve");
def.resolve();
}, 1000);
return def;
};
var fun4 = function (def) {
setTimeout(function () {
console.log("fun4 resolve");
def.resolve();
}, 1000);
return def;
};
$.when(fun1(def1), fun2(def2), fun3(def3),fun4(def4)).done(function () {
console.log("并行执行完毕");
});
//执行结果:
//fun3 resolve
//fun4 resolve
//fun2 resolve
//fun1 resolve
//并行执行完毕

执行的过程如下:

源码分析:

// Deferred helper
when: function( subordinate /* , ..., subordinateN */ ) {
var i = 0,
resolveValues = core_slice.call( arguments ),
length = resolveValues.length, // the count of uncompleted subordinates
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
//20170620 huanhua 这就是 when里面的参数 subordinate必须是返回 deferred对象的函数的原因。
deferred = remaining === 1 ? subordinate : jQuery.Deferred(), // Update function for both resolve and progress values
updateFunc = function( i, contexts, values ) {
return function (value) {
contexts[ i ] = this;
values[i] = arguments.length > 1 ? core_slice.call(arguments) : value;
//20170624 huanhua 在 progess 中时 ,传递的 values 就是 progressValues ,所以 此时 values === progressValues 是成立的,触发 deferred.notifyWith
if( values === progressValues ) {
deferred.notifyWith(contexts, values);
//20170624 huanhua 在 done 时,传递的 values 就是 resolveValues ,所以 此时 values === progressValues 是不成立的,
//在 remaining = 0,全部都执行完了 ,触发 deferred.resolveWith( contexts, values );
} else if ( !( --remaining ) ) {
deferred.resolveWith( contexts, values );
}
};
}, progressValues, progressContexts, resolveContexts; // add listeners to Deferred subordinates; treat others as resolved
if ( length > 1 ) {
progressValues = new Array( length );
progressContexts = new Array( length );
resolveContexts = new Array(length);
for (; i < length; i++) {
//20170624 huanhua 判断传入的个参数是否是 deferred 对象
//如果是
if (resolveValues[i] && jQuery.isFunction(resolveValues[i].promise)) {
//20170625 huanhua 给 when()参数中的各个对象注册方法
resolveValues[ i ].promise()
.done( updateFunc( i, resolveContexts, resolveValues ) )
.fail( deferred.reject )
.progress(updateFunc(i, progressContexts, progressValues));
//如果不是
} else {
--remaining;
}
}
} // if we're not waiting on anything, resolve the master
//20170624 huanhua 如果一个都没参数都没传递,就直接执行
if ( !remaining ) {
deferred.resolveWith( resolveContexts, resolveValues );
}
return deferred.promise();
}

$.when(fun1(def1), fun2(def2), fun3(def3),fun4(def4))返回的就是一个 Deferred.promise对象.

updateFunc = function( i, contexts, values ) {
return function (value) {
contexts[ i ] = this;
values[i] = arguments.length > 1 ? core_slice.call(arguments) : value;
//20170624 huanhua 在 progess 中时 ,传递的 values 就是 progressValues ,所以 此时 values === progressValues 是成立的,触发 deferred.notifyWith
if( values === progressValues ) {
deferred.notifyWith(contexts, values);
//20170624 huanhua 在 done 时,传递的 values 就是 resolveValues ,所以 此时 values === progressValues 是不成立的,
//在 remaining = 0,全部都执行完了 ,触发 deferred.resolveWith( contexts, values );
} else if ( !( --remaining ) ) {
deferred.resolveWith( contexts, values );
}
};
},

$.when(fun1(def1), fun2(def2), fun3(def3),fun4(def4))中,fun1(def1)给这个的返回结果def1注册 done(),并且此时给def1.done()注册的方法是在 done中最后执行,有一段核心代码

//在 remaining = 0,全部都执行完了 ,触发 deferred.resolveWith( contexts, values );
} else if ( !( --remaining ) ) {
deferred.resolveWith( contexts, values );
}

remaining闭包when的参数个数,当所有的参数都执行完了的时候,就调用

$.when(fun1(def1), fun2(def2), fun3(def3),fun4(def4))中的对象 deferred.resolveWith().

通过这个思路我们可以简化个案例,得到这个所有人都要度过河的案例:

var Person = function (name) {
var name = name;
var listDo = [];
this.do = function (fn) {
listDo.push(fn);
};
this.fire = function () {
for (var xh in listDo) {
listDo[xh](name);
}
};
}; var Duhe = function (person1, person2, person3, person4) {
var listDo = [];
var length = arguments.length;
var that = this;
var interval = [3000,2000,2500,1000];
for (var arg in arguments) {
arguments[arg].do(function (name) {
setTimeout(function () {
console.log(name + ":渡河成功!");
if (!(--length)) {
that.fire();
}
}, interval[arg]);
}); };
for (var arg in arguments) {
arguments[arg].fire();
};
this.do = function (fn) {
listDo.push(fn);
return this;
};
this.fire = function () {
for(var xh in listDo){
listDo[xh]();
}
};
}
var duhe = new Duhe(new Person("Person1"), new Person("Person2"), new Person("Person3"), new Person("Person4"), new Person("Person5"));
duhe.do(function () { console.log("所有人员都渡河成功!"); });
//答案:
//Person5:渡河成功!
//Person4:渡河成功!
//Person2:渡河成功!
//Person3:渡河成功!
//Person1:渡河成功!
//所有人员都渡河成功!

在我们实际工作中这个思路很重要。

jquery中的 deferred之 when (三)的更多相关文章

  1. javascript 学习笔记之JQuery中的Deferred对象

    Deffered是Jquery中的一个非常重要的对象,从1.5版本之后,Jquery中的ajax操作都基于Deffered进行了重构,这个对象的处理模式就像其他Javascript框中的Promise ...

  2. jQuery中的Deferred和promise

    promise:http://www.alloyteam.com/2014/05/javascript-promise-mode/ 1 jQuery 中的 Deferred 和 Promises : ...

  3. jQuery中的常用内容总结(三)

    jQuery中的常用内容总结(三) 转载请注明地址:http://www.cnblogs.com/funnyzpc/p/7571998.html 内容提要 选择器(第一节) 选择器的扩展方法(第一节) ...

  4. 深入理解jQuery中的Deferred

    引入 1  在开发的过程中,我们经常遇到某些耗时很长的javascript操作,并且伴随着大量的异步. 2  比如我们有一个ajax的操作,这个ajax从发出请求到接收响应需要5秒,在这5秒内我们可以 ...

  5. 锋利的jQuery ——jQuery中的DOM操作(三)

    一.DOM的操作分类 1>DOM Core   2>HTML-DOM   3>CSS-DOM 二.jQuery中的DOM操作 DOM树 ①查找节点 1)查找元素节点 利用jQuery ...

  6. jQuery 中的 Deferred 和 Promises(转)

    转自:http://www.css88.com/archives/4750/comment-page-1 看前首先了解:Promises/A规范,具体可以看这里,http://www.css88.co ...

  7. jquery中的 deferred之 then (二)

    例: var def = $.Deferred(); var prs1 = def.then(function (val) { var result = val + "_123" ...

  8. jQuery中的deferred对象和extend方法

    1⃣️deferred对象 deferred对象是jQuery的回调函数解决方案,它是从jQuery1.5.0版本开始引入的功能 deferred对象的方法 (1) $.Deferred() 生成一个 ...

  9. jquery中ajax方法返回的三种数据类型:text、json、xml;

    1.当dataType:"text"时,处理页面用的是DBDA类中的Strquery()方法,所以返回的数据是下面这样的,所以要对返回来的数据用split根据“|”和“^”来分割, ...

随机推荐

  1. MQTT研究之EMQ:【JAVA代码构建X509证书】

    这篇帖子,不会过多解释X509证书的基础理论知识,也不会介绍太多SSL/TLS的基本信息,重点介绍如何用java实现SSL协议需要的X509规范的证书. 之前的博文,介绍过用openssl创建证书,并 ...

  2. 记录一次MyEclipse打开jsp文件出现Error的解决办法

    今天正在忙着写项目,在打开一个项目内的jsp文件时发现我亲爱的代码消失了. 最后从网上找到了解决办法,希望可以帮到有需要的人,也作为个人记录 第一步:找到安装路径MyEclipse\configura ...

  3. 同一台电脑配置多个JBoss

    在jboss中找到对应的文件,修改对应文件端口可解决两个以上jboss的端口冲突问题 不同的jboss修改的端口要区别开来,本例所用jboss版本为JBoss4.2.2.GA 文件端口: 8083,1 ...

  4. DSP 运行时间计算函数--_itoll(TSCH,TSCL);

    DSP OMAP 程序耗时测定 CPU周期 两种方法 利用TSCL和TSCH来计算时钟周期,这两天看了一下如何他们 DSP开发,测量某个函数或某段代码的cycles消耗是经常要做的 事情,常用的pro ...

  5. 简易Asset工作流

    前言: 当前比较主流的制作流程都可以按顺序细分为三个部分:资产环节(asset section),镜头环节(shot section),合成环节(composite section). 考虑到单一资产 ...

  6. 解决WIN7第一次开机冷启动QQ未响应的办法

    为什么WIN7第一次开机冷启动QQ未响应?WIN10就没事? http://bbs.wuyou.net/forum.php?mod=viewthread&tid=409516&extr ...

  7. Unity Input,生命周期,Light,获取组件

    1.     递归方法遍历获取指定子物体 知识点:递归的使用:transform.childCount.GetChild(index) 2.  Input输入控制类,检测玩家输入 知识点: Input ...

  8. ionic2 调用 cordova非本地化native 插件方法

    1,在项目中添加你的插件     cordova plugin add puginId|puginName|puginUrl|puginPath 2,查看插件clobbers标记 打开项目目录plug ...

  9. C#添加VisionPro控件问题

    安装完VisionPro8.2版本以后,用VS2013调用时,没有默认在工具箱内,那么就需要手动添加了,选择菜单栏---->工具----->选择工具箱项,如下图所示:           ...

  10. iOS移动开发CoreDate讲解

    ----欢迎------- 在移动端开发,数据持久化保存是基本要素,没钱在2014年之后退出了coredate,本持久化基于oc作为开发,方便程序人员操作.与SQL数据库,MySQL相比,优点颇多. ...