本系列文章讲介绍这个Deferred东西到底拿来干什么,从1.5版本加进来,jQuery的很多代码都重写了。直接先上源码分析了,清楚了源码分析,下节将讲具体的应用 以及应用场景。

创建对象 var def=$.Deferred(); 包含 done,resolve,resolveWith,reject,rejectWith,isResolved等等方法

这套系列文章主要是分析jQuery的源码

jQuery.extend({
// Create a simple deferred (one callbacks list)
_Deferred: function () {
var // callbacks list
callbacks = [],
//储存上下文环境和函数参数 stored [ context , args ]
fired,
//避免函数提前触发
firing,
//标示这个延迟对象是否被取消了 cancel方法
cancelled,
// the deferred itself
deferred = { /*把要依次处理的函数(arguments)[可以是函数列表,也可以是函数数组]加入到队列表(callbacks)中,,返回 deferred 对象
*/
done: function () {
if (!cancelled) {
//arguments函数参数对象,可以看出jQuery喜欢把一个函数所有的参数定义到头部
var args = arguments,
i,
length,
elem,
type,
_fired;
//如果这个延迟对象已经触发,用 _fired保存[context , args ]
if (fired) {
_fired = fired;
fired = 0; //修改fired=0,以便以后继续调用done()函数
}
for (i = 0, length = args.length; i < length; i++) {
elem = args[i];
//这里调用了静态的$.type方法
type = jQuery.type(elem);
//do([f1,f2]),继续回头调用这个方法
if (type === "array") {
deferred.done.apply(deferred, elem);
} else if (type === "function") {
//callbacks 函数集合
callbacks.push(elem);
}
}
//如果这个延迟对象已触发,立即调用resolveWith方法
if (_fired) {
deferred.resolveWith(_fired[0], _fired[1]);
}
}
return this;
}, /*在给定的上下文(context默认为deferred=this对象)中执行队列,清除队列 resolve 执行队列,返回 deferred 对象
*/
resolveWith: function (context, args) {
//没有被取消&&没有被已经触发&&避免提前触发
if (!cancelled && !fired && !firing) {
// make sure args are available (#8421)
args = args || [];
//阻止callbacks提前触发
firing = 1;
try {
//循环执行回调函数队列,不错的写法
while (callbacks[0]) {
callbacks.shift().apply(context, args);
}
}
finally {
//修改deferred里的变量状态,firing=0 阻止回调函数触发,fired store[context,args]
//其实这里的fired firing相当于deferred对象的私有变量,通过改变他的值判断函数队列的执行。
fired = [context, args];
firing = 0;
}
}
return this;
}, /* resolve with this as context and given arguments,这里的this指代deferred对象
*/
resolve: function () {
//当resolve后,以后done()进来的函数都会立即执行,这个在$(function(){});运用的非常好!这里$(function(){})=
$(document).ready(function(){})原因可以在init实例化的函数中看到
if (jQuery.isFunction(selector)) {return rootjQuery.ready(selector)};
deferred.resolveWith(this, arguments);
return this;
}, /* Has this deferred been resolved?为什么要用!!了,这样才能返回true或者false,比如!!1 !!0 通过deferred对象私有变量判断是否已被
resolved
*/
isResolved: function () {
return !!(firing || fired);
}, // Cancel cancelled=1可以阻止callbacks触发,并清空callbacks.这个函数其实我们自己用不到jQuery后面扩展我们使用的Deferred对象时候会取消掉
cancel: function () {
cancelled = 1;
callbacks = [];
return this;
}
}; return deferred;
}, /*这个$.Deferred()才是给我们使用的,然后根据私有的_Deferred对象扩展出fail,reject等等,这个其实跟done,resolve是同理的,所有作者这里进行了代码公用,只是取了个不同的名字
*/
Deferred: function (func) {
//建立两个私有的延迟对象,扩展deferred,用failDeferred去代替fail ,rejectWith ,reject
var deferred = jQuery._Deferred(),
failDeferred = jQuery._Deferred(),
promise;
//增加错误的deferred methods,and promise
jQuery.extend(deferred, {
//两个参数,一个成功回调函数队列,一个失败回调函数队列
then: function (doneCallbacks, failCallbacks) {
deferred.done(doneCallbacks).fail(failCallbacks);
return this;
},
//不管失败与否都调用
always: function () {
// done的上下文设置为deferred,fail的上下文设置为this
// done和fail的上下文不一致吗?一致!在这里this等于deferred
//这行代码同 deferred.done(arguments).fail(arguments);这里感觉有点怪,为了让这个函数队列arguments执行,不得不在done和fail队列同时添加一种回调函数队列然后 return this;但是后面后删除done队列或者fail队列,看那个函数被执行了 答案在这deferred.done(failDeferred.cancel).fail(deferred.cancel);
return deferred.done.apply(deferred, arguments).fail.apply(this, arguments);
},
//这几个方法跟上面done,resolveWith,resolve,isResolve的同理
fail: failDeferred.done,
rejectWith: failDeferred.resolveWith,
reject: failDeferred.resolve,
isRejected: failDeferred.isResolved,
pipe: function (fnDone, fnFail) {
//暂时没搞懂这个拿来干什么,直到怎么理解的可以留下言谢谢
return jQuery.Deferred(function (newDefer) {
//遍历一个对象
jQuery.each({
done: [fnDone, "resolve"],
fail: [fnFail, "reject"]
}, function (handler, data) {
var fn = data[0],
action = data[1],
returned;
if (jQuery.isFunction(fn)) {
deferred[handler](function () {
returned = fn.apply(this, arguments);
if (returned && jQuery.isFunction(returned.promise)) {
returned.promise().then(newDefer.resolve, newDefer.reject);
} else {
newDefer[action + "With"](this === deferred ? newDefer : this, [returned]);
}
});
} else {
deferred[handler](newDefer[action]);
}
});
}).promise();
}, /* 返回一个包含 done fail isResolved isRejected promise then always pipe的deferred对象,不让外部修改状态,只能读状态
*/
promise: function (obj) {
if (obj == null) {
if (promise) {
return promise;
}
promise = obj = {};
}
var i = promiseMethods.length;
//又一个经典的循环方法,这样更快,这样i--是跟0比较,而不用跟promiseMethods.length比较,学到吧
while (i--) {
obj[promiseMethods[i]] = deferred[promiseMethods[i]];
}
return obj;
}
});
// 成功队列执行完成后,会执行失败带列的取消方法
// 失败队列执行完成后,会执行成功队列的取消方法
// 确保只有一个函数队列会被执行,即要么执行成功队列,要么执行失败队列;
// 即状态只能是或成功、或失败,无交叉调用
deferred.done(failDeferred.cancel).fail(deferred.cancel);
// Unexpose cancel
delete deferred.cancel;
//如果有函数传进来则立即执行 传入deferred对象,调用回调函数,如def=$.Deferred(funciton(defer){ defer.resolve;.. })
if (func) {
func.call(deferred, deferred);
}
//返回deferred对象
return deferred;
}, /* Deferred helper
异步队列工具函数
firstParam:一个或多个Deferred对象或JavaScript普通对象
*/
when: function (firstParam) {
//如果参数的长度等于1,并且存在promise函数,表面是一个deferred对象,它这样判断传入的参数是个deferred对象。如果都不满足则新建一个$.Deferred()对象
var args = arguments,
i = 0,
length = args.length,
count = length,
deferred = length <= 1 && firstParam && jQuery.isFunction(firstParam.promise) ?
firstParam :
jQuery.Deferred();
// 构造成功(resolve)回调函数
function resolveFunc(i) {
return function (value) {
// 如果传入的参数大于一个,则将传入的参数转换为真正的数组 sliceDeferred=[].slice
args[i] = arguments.length > 1 ? sliceDeferred.call(arguments, 0) : value;
//直到count为0的时候
if (!(--count)) {
// Strange bug in FF4:
// Values changed onto the arguments object sometimes end up as undefined values
// outside the $.when method. Cloning the object into a fresh array solves the issue
//resolve deferred 响应这个deferred对象,上面这句话好像是解决一个奇怪的bug
deferred.resolveWith(deferred, sliceDeferred.call(args, 0));
}
};
}
if (length > 1) {
for (; i < length; i++) {
//存在agrs[i]并且是args[i]是deferred对象,那这样的话作者怎么不直接jQuery.isFunction(args[i].promise),感觉多判断了,作者也蒙了吧
if (args[i] && jQuery.isFunction(args[i].promise)) {
//执行一次resolveFunc(i)count就减少一个
args[i].promise().then(resolveFunc(i), deferred.reject);
} else {
// 计数器,表示发现不是Deferred对象,而是普通JavaScript象 ,反正最后只要count==0才能resovle deferred
--count;
}
}
if (!count) {
deferred.resolveWith(deferred, args);
}
} else if (deferred !== firstParam) { //如果只传了一个参数,而这个参数又不是deferred对象,则立即resolve
deferred.resolveWith(deferred, length ? [firstParam] : []);
}
return deferred.promise(); //返回deferred只读视图
}
});

  

jQuery Deferred对象详细源码分析(-)的更多相关文章

  1. jQuery 2.0.3 源码分析Sizzle引擎解析原理

    jQuery 2.0.3 源码分析Sizzle引擎 - 解析原理 声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 先来回答博友的提问: 如何解析 div > p + ...

  2. Vue3中的响应式对象Reactive源码分析

    Vue3中的响应式对象Reactive源码分析 ReactiveEffect.js 中的 trackEffects函数 及 ReactiveEffect类 在Ref随笔中已经介绍,在本文中不做赘述 本 ...

  3. jQuery deferred应用之ajax详细源码分析(二)

    在上一节中,我只贴出了$.Deferred的源码分析,并没用讲解怎么使用它,现在我们先看看$.ajax是如何使用它,让我们进行异步任务的处理. 如果没看上节的代码,请先稍微了解一下jQuery Def ...

  4. jQuery 2.0.3 源码分析 Deferred概念

    JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而回调函数中则包含了后续的工作.这也是造成异步编程困难的主要原因:我们一直习惯于“线性”地编写代码 ...

  5. jQuery 2.0.3 源码分析 Deferred(最细的实现剖析,带图)

    Deferred的概念请看第一篇 http://www.cnblogs.com/aaronjs/p/3348569.html ******************构建Deferred对象时候的流程图* ...

  6. jQuery 2.0.3 源码分析 Deferrred概念

    转载http://www.cnblogs.com/aaronjs/p/3348569.html JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而 ...

  7. jQuery 2.0.3 源码分析core - 整体架构

    拜读一个开源框架,最想学到的就是设计的思想和实现的技巧. 废话不多说,jquery这么多年了分析都写烂了,老早以前就拜读过, 不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery ...

  8. jQuery.extend()方法和jQuery.fn.extend()方法源码分析

    这两个方法用的是相同的代码,一个用于给jQuery对象或者普通对象合并属性和方法一个是针对jQuery对象的实例,对于基本用法举几个例子: html代码如下: <!doctype html> ...

  9. jQuery 2.0.3 源码分析core - 选择器

         声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢!      打开jQuery源码,一眼看去到处都充斥着正则表达式,jQuery框架的基础就是查询了,查询文档元素对象 ...

随机推荐

  1. Linux下的RTC子系统

    转自:http://blog.csdn.net/weiqing1981127/article/details/8484268 实时时钟的作用主要是为操作系统提供一个可靠的时间,并在断电下,RTC时钟也 ...

  2. 免证书发布ipa文件真机测试

    首先设备得越狱 众所周知,在Xcode上开发的程序只能在模拟器中运行,如果要放到真机上则要花费99美金购买开发者证书iDP.这严重阻碍了我等草根开发者探索的脚步.写个小程序,同学间分享一下这个小小的愿 ...

  3. 【网络爬虫】【java】微博爬虫(四):数据处理——jsoup工具解析html、dom4j读写xml

    之前提到过,对于简单的网页结构解析,可以直接通过观察法.手工写正则解析,可以做出来,比如网易微博.但是对于结构稍微复杂点的,比如新浪微博,如果还用正则,用眼睛一个个去找,未免太麻烦了. 本文介绍两个工 ...

  4. 前端HTML 与css 整理(未完)

    HTML 中的标签存放于文本文件中 需要按照以下固定的文档结构组织:<!DOCTYPE HTML><html> <head>头部相关信息 </head> ...

  5. 洛谷 - P2257 - YY的GCD - 莫比乌斯反演 - 整除分块

    https://www.luogu.org/problemnew/show/P2257 求 \(n,m\) 中 \(gcd(i,j)==p\) 的数对的个数 求 $\sum\limits_p \sum ...

  6. UnityEngine中Animator相关类的说明

    ---------------------------------------------------------------------- Animator 这个单独写,比较多 AnimationC ...

  7. Pycharm2018.3.1永久激活

    Pycharm Professional 2018.3.1 版已正式发布,新版本添加对Python3.7的支持.作为强大的开发工具,但每次注册让人头疼,本着分享的心态,提供以下解决方案,亲测有效!本方 ...

  8. Java并发编程笔记

    进程:程序的一次运行活动. 线程:程序的一个控制流程.用于执行一个任务.是cpu进行调度的最小单位. 死锁:所有的线程继续执行所需要的资源都被其他线程占用,导致所有线程都不能继续执行. 死锁的情景:1 ...

  9. D - Fliptile

    #include <stdio.h> #include <iostream> #include <math.h> #include <algorithm> ...

  10. java关于方法参数传递的相关问题讨论

    我们知道,java中定义变量的目的有两个: 1.防止被垃圾回收机制回收,毕竟如果没有明确指向真实物理内存的'代号'很大可能会被java垃圾回收机制当作垃圾回收. 2.便于引用,方便处理. packag ...