Deferred

Posted 修身齐家治国平天下

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Deferred相关的知识,希望对你有一定的参考价值。

上文中提到了Promise构造函数,就不得不提Deferred(延迟)对象了,其实,让Deferred对象得到推广的便是其在jQuery中的使用,本文就jQuery中对Deferred对象的使用进行探讨。

1、Deferred的概念

延迟对象,在jQuery的1.5引入,是通过调用jQuery.Deferred()方法创建一个可链式调用的工具对象。 它可以注册多个回调到回调队列, 调用回调队列,准备代替任何同步或异步函数的成功或失败状态。

延迟对象是可链式调用的,类似于jQuery对象是可链接的方式,  但它有其自己的方法。 创建一个Deferred(延迟)对象后,你可以通过方法 直接从对象创建或者链式调用 或 保存对象的一个变量,调用该变量的一个或多个方法。

 jQuery.Deferred()基于Promises/A规范实现,因为jQuery本身的设计风格,jQuery.Deferred()并没有完全遵循Promises/A规范。
jQuery在1.5版本中首次引入了Deferred。你可以通过jQuery.Deferred() 在未来某个时候 得到 ‘延时’返回值。 在此之前是无法单独使用的,Deferred作为对ajax模块较大重写的一部分添加进来。1.5和1.6版本包含Deferred功能,可以使$.ajax() 接收调用完成及请求出错的回调,但却存在严重的耦合。新版本的jQuery提供了一些增强的方式来管理回调,提供更加灵活的方式建立回调,而不用关心原始的回调是否已经触发。 jQuery的Deferred对象支持多个回调绑定多个任务,任务本身既可以是同步也可以是异步的。
Deferred对象有三种状态,pending:未完成,resolved:已完成,rejected:未完成。(注:和Promise对象中的状态一模一样呢!)
 
2、初试牛刀

 先看看$.Deferred是 什么?

可以看出Deferred只是一个定义在jQuery上的普通方法,没有太多的信息,那我们调用一下试试。

我们又可以看出,其实Deferred函数其实返回的是一个对象,这个对象也有always、catch、done、fail、notity、notifyWith、pipe、promise、progress、reject、rejectWith、resolve、resolveWith、state、then方法。

Deferred有三个状态,pending:未完成,resolved:操作成功,rejected: 操作失败

当deferred1对象调用resolved时,deferred1中的done方法会被调用,当deferred1对象调用rejected时,deferred1的fail方法会被调用,比如

var deferred1 = $.Deferred();
deferred1.done(function (data) {
    console.log(\'success: \',  data)
})
deferred1.fail(function (err) {
    console.log(\'err: \', err)
})
setTimeout(function(){
  deferred1.resolve(\'victory\')
},200)

//输出success: victory

3、Promise对象的方法

我们接着聊notify和progress。

progress()用来指定一个回调函数,当调用notify()方法时,该回调函数将执行。它的用意是提供一个接口,使得在非同步操作执行过程中,可以执行某些操作,比如定期返回进度条的进度。

var userProgress = $.Deferred();
var $profileFields = $("input");
var totalFields = $profileFields.length;
userProgress.progress(function (filledFields) {
    var pctComplete = (filledFields/totalFields)*100;
    $("#progress").html(pctComplete.toFixed(0));
}); 
userProgress.done(function () {
    $("#thanks").html("Thanks for completing your profile!").show();
});
$("input").on("change", function () {
    var filledFields = $profileFields.filter("[value!=\'\']").length;
    userProgress.notify(filledFields);
    if (filledFields == totalFields) {
        userProgress.resolve();
    }
});

 

现在接着聊then方法,then方法接收三个回调函数,第一个参数是resolve时调用的回调函数,第二个参数是reject时调用的回调函数,第三个参数是progress()方法调用的回调函数。

 

和谈Promise一样,现在我们也Deferred来封装一个getJSON函数,实现AJAX的例子

var getJSON = function(url) {
    var deferred = $.Deferred();
   var client = new XMLHttpRequest(); client.open(\'GET\', url); client.onreadystatechange = function(){ if (this.readyState !== 4) { return } if (this.status === 200) { deferred.resolve(this.response) } else { deferred.reject(new Error(this.statusText)) } } return deferred } getJSON(\'/db.json\').then(function(json){ console.log(\'Result:\', json) }, function(error){ console.log(\'error:\', error) })

 

4、Deferred中的promise对象

大多数情况下,我们不想让用户从外部更改deferred对象的状态。这时,你可以在deferred对象的基础上,返回一个针对它的promise对象。我们可以把后者理解成,promise是deferred的只读版,或者更通俗地理解成promise是一个对将要完成的任务的承诺。

你可以通过promise对象,为原始的deferred对象添加回调函数,查询它的状态,但是无法改变它的状态,也就是说promise对象不允许你调用resolve和reject方法。

function getPromise(){
    return $.Deferred().promise();
}
try{
    getPromise().resolve("a");
} catch(err) {
    console.log(err);
}
//会进入catch方法,显示TypeError {}

jQuery的ajax() 方法返回的就是一个promise对象。

 


以上是关于Deferred的主要内容,如果未能解决你的问题,请参考以下文章

爬虫日记(101):Twisted:使用Deferred重构异常代码

爬虫日记(102):Twisted:使用Deferred重构服务器代码

jquery-deferred应用

爬虫日记(100):Twisted:使用Deferred重构回调函数管理

javascript异步代码的回调地狱以及JQuery.deferred提供的promise解决方式

jq Deferred的源码实现