从1.5开始,JQuery引入了Deferred对象,应用这个对象,针对一个行为可以注册多个回调函数,并能将行为的调用结果进行传递。以下用一些例子来说明这个对象的强大功能。

楔子:

以下的代码是用来获取一个文件的内容,获取完毕后弹出文件的内容。

<html>

    <head>

        <title></title>

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>

    </head>

    <body>

    <script type="text/javascript" language="javascript">

 

     $(function () {

     $.get(

"content.txt",

function (resp) {

alert(resp);

}

);

     });

 

</script>

    </body>

</html>

 

执行结果如下:

定时炸弹--JQuery中的Deferred对象_javascript

 

1. 延迟调用

 

     以上的这段程序,如果我不想马上执行,而是想在这里注册一下,在将来的某个时候让他执行。如果用传统的方法很难实现,这里Deferred的对象的优势就显示出来了。请看下面的代码:

     var deferred = $.Deferred();

     deferred.done(function () {

     $.get(

"content.txt",

function (resp) {

alert(resp);

}

);

     });

 

alert("other things...")

 

 

deferred.resolve();

 

上面的代码中,我先将要执行的代码写上,然后去做其他的事情。等到我想要这段代码执行的时候,只要调用 deferred.resolve();就可以了。

当然,也可以将这个deferred对象做为参数传递到其他地方,在其他地方调用deferred.resolve()来让这段代码执行。

我们可以把Deferred对象想象成一颗定时炸弹,把它埋在一个地方,以后我们想让它爆炸的时候,只要调用一下deferred.resolve()。

 

2. deferred.reject

deferred.reject与deferred.resolve正好相反,后者是让指定的行为正常执行,而前者将指定的行为拒绝,不让它执行。请看下面的代码:

     var deferred = $.Deferred();

     deferred.then(function () {

     $.get(

"content.txt",

function (resp) {

alert(resp);

}

);

     },

 

function () {

alert("failed");

}

);

 

     //alert("other things...")

 

deferred.reject();

 

执行的结果是弹出failed.

 

可以看出,reject以后,会发送到failCallbacks回调函数中。

 

3. deferred.done()和deferred.then()

deferred.done()和deferred.then()都是在Deferred对象被Resolve或者rejected的时候调用的。请看下面的代码:

     var deferred = $.Deferred();

     deferred.done(function () {

     alert("done");

     });

     deferred.then(function () {

     alert("then");

     });

 

deferred.resolve();

 

执行结果是先弹出done,后弹出then.

 

如果我们把done和then的顺序调换一下:

     var deferred = $.Deferred();

     deferred.then(function () {

     alert("then");

     });

     deferred.done(function () {

     alert("done");

     });

 

deferred.resolve();

这次的执行结果就是先弹出then,后弹出done。

看来deferred.then()和deferred.then()谁放在前面谁先执行。

 

deferred.done()和deferred.then()都可以附加多个回调函数,请看下面的代码(注意中括号的使用):

     function doneFunc1() {

     alert("doneFunc1");

     }

 

     function doneFunc2() {

     alert("doneFunc2");

     }

 

     function thenFunc1() {

     alert("thenFunc1");

     }

 

     function thenFunc2() {

     alert("thenFunc2");

     }

 

     var deferred = $.Deferred();

     deferred.then([thenFunc1,thenFunc2]);

     deferred.done([doneFunc1,doneFunc2]);

 

deferred.resolve();

 

deferred.done()和deferred.then()两者的用法很相似,唯一的区别就是参数不同:

deferred.then( doneCallbacks, failCallbacks )

deferred.done( doneCallbacks [, doneCallbacks] )

 

从函数定义可以看出,deferred.then()可以添加FailCallBack,而deferred.done不能。

 

4. deferred.fail

deferred.fail用来添加一个处理事件,该处理事件在Deferred对象被reject时执行。请看下面的例子:

     var deferred = $.Deferred();

     deferred.fail(function () {

     alert("fail!");

     });

 

deferred.reject();

 

5. deferred.always

   deferred.done()和deferred.then()在deferred对象的行为成功时执行,deferred.fail在deferred对象的行为失败时执行,而deferred.always则在所有的时候都执行。

   用这四个函数,我们可以模拟传统编程中的try,catch, finally.请看下面的例子:

     var deferred = $.Deferred();

     deferred.done(function () {

     alert("try 1");

     });

     deferred.then(function () {

     alert("try 2");

     });

     deferred.fail(function () {

     alert("catch");

     });

     deferred.always(function () {

     alert("finally");

     });

 

以上的代码,当我们分别调用deferred.resolve()和deferred.reject()时,会看到与try,catch,finally同样的效果。

 

6. deferred.notify

deferred.resolve和deferred.reject都属于终结性的行为,也就是说,调用了deferred.resolve和deferred.reject后,再也不能对deferred对象进行状态上的改变(resolve, reject, notify, resolveWith, rejectWith, 和 notifyWith)。下面的例子中,第二个reject不会执行。

     var deferred = $.Deferred();

     deferred.done(function () {

     alert("done");

     });

     deferred.fail(function () {

     alert("fail");

     });

 

     deferred.resolve();

     deferred.reject();

 

如果我们想让deferred对象做一些事情,而又不想终结该deferred对象,该怎么办哪?这就是deferred.notify方法的作用。请看下面的例子:

     var deferred = $.Deferred();

     deferred.progress(function (args) {

     alert(args);

     });

 

     deferred.notify("notify1");

     deferred.notify("notify2");

     deferred.resolve();

 

这个例子的执行结果会依次弹出notify1和notify2.

 

7. deferred.progress

deferred.progress方法在第6条的例子中已经见到过,它就是和deferred.notify配对使用。

 

8. deferred.promise

有这样一种情况:我们暴露出一个Deferred对象给其他函数使用,但是只想让用户向上面挂回调函数,不想让用户改变这个Deferred对象的状态。就好像电视节目,很多人都可以定制,但是何时播放什么节目,观众个人是不能改变的。这就是deferred.promise方法的作用。

deferred.promise方法返回的Promise对象,允许其他函数添加回调函数 (done, fail, always, pipe, progress, 和 state) ,但是其他函数不能改变这个对象的状态 (resolve, reject, notify, resolveWith, rejectWith, 和 notifyWith) 。

请看下面的例子:

     function GetPromise() {

     var deferred = $.Deferred();

 

     deferred.resolve();

     return deferred.promise();

 

}

 

var promise = GetPromise();

promise.done(function () {

alert("promise.done");

});

promise.always(function () {

alert("promise.always");

});

 

9. deferred.isRejected 和 deferred.isResolved

deferred.isRejected 和 deferred.isResolved是用来指示Deferred对象是被resolve了还是reject了。

     var deferred = $.Deferred();

     deferred.then(function () {

     $.get(

"content.txt",

function (resp) {

alert(resp);

}

);

     }

);

 

deferred.reject();

 

alert(deferred.isResolved());

以上的代码,执行结果是弹出false

 

deferred.isRejected 和 deferred.isResolved在JQuery1.5加入,从JQuery1.7开始,使用deferred.state()代替。

 

10. deferred.pipe

  deferred.resolve,deferred.reject等函数中都可以传递参数,比如下面的例子:

     var deferred = $.Deferred();

     deferred.done(function (arg) {

     alert(arg);

     });

 

deferred.resolve( 5 );

 

对于这个例子,如果我们想让参数在传递给回调函数之前进行一些转换,该怎么办哪?这就是deferred.pipe的作用。pipe顾名思义是管道的意思,就是让参数(在这里例子中是5)经过一个管道,然后到达回调函数。在这个管道中,可以对这个参数进行任意加工处理。这里需要注意的是,这里的管道是我们另外接出来的一个分支,而不会影响到主管道。

请看下面的例子:

     var deferred = $.Deferred();

     deferred.done(function (arg) {

     alert(arg);

     });

     var filtered = deferred.pipe(function (arg) {

return arg + "(processed by pipe)"

});

filtered.done(function (arg) {

alert("in filtered:" + arg);

});

deferred.resolve(5);

 

这个例子会弹出两次,一次弹出5,一次弹出in filtered:5(processed by pipe),展示了主管道和我们自己接出来的管道(filtered)的回调函数的两种不同执行结果。