先来看使用案例:

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. mvc项目远程发布到windows server服务器

    1.安装IIS的时候需要将这两个选项勾选起来 2.确保 管理服务委派 这个选项存在 3.添加委派规则 4.配置IIS管理用户,后续需要用这个用户进行发布连接 5.配置站点的IIS权限 选择刚才在前面设 ...

  2. jq源码判断数据类型

    4.Object.prototype.toString.call() 1 var a = Object.prototype.toString; 2 3 console.log(a.call(" ...

  3. flutter mac 下安装

  4. Eclipse Memory Analyzer 分析内存泄露

    OutOfMemoryError示例 代码 package com.walson.heap; import java.util.ArrayList;import java.util.List; /** ...

  5. 执行代码出现ImportError:attempted relative import with no known parent package

    前言 在这篇文章中,我将会解析 ImportError: attempted relative import with no known parent package 这个异常的原因.当你在运行的py ...

  6. 知识点:Mysql 索引原理完全手册(2)

    知识点:Mysql 索引原理完全手册(1) 知识点:Mysql 索引原理完全手册(2) 知识点:Mysql 索引优化实战(3) 知识点:Mysql 数据库索引优化实战(4) 八. 联合索引与覆盖索引 ...

  7. Linux下自己实现getopt功能

    实现思路: 通过 pid_t pid = getpid() 来获取当前进程id,然后 sprintf(fname, "/proc/%d/cmdline", pid); 读取fnam ...

  8. GPIO输入输出各种模式(推挽、开漏、准双向端口)详解

    转自:https://blog.csdn.net/techexchangeischeap/article/details/72569999 概述 能将处理器的GPIO(General Purpose ...

  9. Linq to SQL -- Insert、Update、Delete

    Insert/Update/Delete操作 插入(Insert) 1.简单形式 说明:new一个对象,使用InsertOnSubmit方法将其加入到对应的集合中,使用SubmitChanges()提 ...

  10. JAVA 8 函数式接口--Consumer

    从JDK8开始java支持函数式编程,JDK也提供了几个常用的函数式接口,这篇主要介绍Consumer接口.文本介绍的顺序依次为: 源码介绍 使用实例 jdk内对Consumer的典型使用 扩展类介绍 ...