Deferred首次出现在jQuery 1.5中,在jQuery 1.8之后被改写,它的出现抹平了javascript中的大量回调产生的金字塔,提供了异步编程的能力,它主要服役于jQuery.ajax。
Deferred就是让一组函数在合适的时机执行,在成功时候执行成功的函数系列,在失败的时候执行失败的函数系列,这就是Deferred的本质。简单的说,模型上可以规划为两个数组来承接不同状态的函数——数组resolve里的函数列表在成功状态下触发,reject中的函数在失败状态下触发。
这篇文章主要分为以下知识,和上一篇博文《读jQuery源码之 - Callbacks》关联。
什么是Deferred
初窥Deferred
Deferred本身就是承接一组函数,在异步中执行这组函数,过去的我们是这样编写异步代码的:
var resolve = function () { console.log('成功'); }, //定义一个失败状态下运行的函数 reject = function () { console.log('失败'); }; //模拟服务器请求,正在等待服务器响应ing..... setTimeout(function (status) { if (status === 200) resolve(); else reject(); }, 1000);
如果用Deferred那么上面的代码则应该是下面这个样子:
var deferred = new Deferred(); //先将成功和失败的函数委托到Deferred deferred.resolve(function () { console.log('成功'); }).reject(function () { console.log('失败'); }).resolve(function () { console.log('我还想再追加一个成功的函数'); }); //当改变状态的时候,会自动触发成或者失败的函数 setTimeout(function (status) { if (status === 200) deferred.resolve(); else deferred.reject(); });
Deferred有点Callbacks的特质,不过是Callbacks的逼格提升版(异步定制版)。在Callbacks的基础上提升了对于异步函数的管理——本身的使用和Callbacks一样:承接一组函数,触发执行。
Deferred主要服役于jQuery.ajax(),使用了Deferred的ajax代码如下:
//Deferred的应用(ajax) $.ajax('demo.html').done(function () { console.log('ajax成功'); }).fail(function () { console.log('ajax失败'); }).done(function () { console.log('ajax成功,追加一条函数处理我们自己的事情...'); });
jQuery把Deferred对象封装到ajax中,jQuery.ajax()中,jQuery维护ajax请求的发起到接收,而使用jQuery的开发者,只关注ajax的结果即可,众所周知,ajax是异步的,而我们这些成功后(失败后)要执行的函数,从代码的层面上,是线性的编写的——正是Deferred提供了这样异步编程的能力。
回调函数的定义(委托)和回调函数的执行
Deferred切割了回调函数和执行时机两个概念。就是把回调函数的定义和回调函数的执行这两个概念给分离开,同一时间专注一个概念,这样代码就能够线性的编写下去,Deferred主要应用于这种回调函数的多层嵌套,而这种情况多发生于异步(当然它也确实是为异步量身打造),所以就叫Deferred——让你异步的代码,看起来跟像同步执行一样。当然它并不局限与异步。
Deferred在Callbacks基础上做的二次封装,它封装了一组状态,每组状态对应一个Callbacks对象。我们还是说的再简单通俗一点吧:Deferred主要有三个状态作为工作标志:成功、失败、无状态。成功失败还好点,这个“无状态”是个神马意思??
Deferred本身就是根据状态来触发的,成功状态下触发成功状态的函数,失败状态下触发失败状态的函数,最后这个无状态就是:既不成功,也不失败,但是每次要触发相应的函数——用于文件上传,在文件上传的ajax中,要和服务器一直保持请求,每次请求既不代表成功也不代表失败,那么这个无状态就是最好的标志。
Deferred本质上的实现就是用数组专门用来存放对应状态的函数,然后循环执行。就是有三个数组:代表成功状态下执行的resolve函数数组和代表失败状态下执行的reject函数数组, 还有一个每次触发都会执行的progress数组。