jQuery的deferred对象解析

1.指定同一操作的多个回调函数

		$.ajax("test.html")
			.done(function () { console.log("哈哈,成功了!"); })
			.fail(function () { console.log("出错啦!"); })		//如果fail,就不会执行后面的:第二个回调函数!
			.done(function(){ console.log("第二个回调函数!");} );

jQuery的deferred对象解析

2.为多个操作指定回调函数

deferred对象的另一大好处,就是它允许你为多个事件指定一个回调函数,这是传统写法做不到的。

请看下面的代码,它用到了一个新的方法$.when()

     <script>
        $.when($.ajax("test.html"), $.ajax("test1.html"))
            .done(function (xhr) {
                console.log(xhr);  //这里的xhr没有返回test1
                 console.log("哈哈,成功了!"); } //都成功了,就运行done()指定的回调函数
                 )

            .fail(function () { console.log("出错啦!"); }); //如果有一个失败或都失败了,就执行fail()指定的回调函数。
    </script>

这段代码的意思是,先执行两个操作$.ajax("test.html")和$.ajax("test1.html"),如果都成功了,就运行done()指定的回调函数;如果有一个失败或都失败了,就执行fail()指定的回调函数。

jQuery的deferred对象解析

3.普通操作的回调函数接口(上)

jQuery.when()

jQuery.when( deferreds )
deferreds
类型: Deferred 或 Promise 或 Thenable
零个或多个延迟对象,或者普通的JavaScript对象。

在多个延迟对象传递给jQuery.when() 的情况下,该方法根据一个新的“宿主” Deferred(延迟)对象,跟踪所有已通过Deferreds聚集状态,返回一个Promise对象。

1.当所有的延迟对象被解决(resolve)时,“宿主” Deferred(延迟)对象才会解决(resolved)该方法,

2.或者当其中有一个延迟对象被拒绝(rejected)时,“宿主” Deferred(延迟)对象就会reject(拒绝)该方法。

3.如果“宿主” Deferred(延迟)对象是(resolved)解决状态时, “宿主” Deferred(延迟)对象的 doneCallbacks (解决回调)将被执行。

4.参数传递给 doneCallbacks提供这解决(resolved)值给每个对应的Deferreds对象,并匹配Deferreds传递给 jQuery.when()的顺序

        var d1 = $.Deferred();
        var d2 = $.Deferred();
        var d3 = $.Deferred();

        $.when(d1, d2, d3).done(function (v1, v2, v3) {
            console.log(v1); // v1 is undefined		4.匹配Deferreds传递给 `jQuery.when()`的顺序
            console.log(v2); // v2 is "abc"
            console.log(v3); // v3 is an array [ 1, 2, 3, 4, 5 ]
        }).fail(function (s1, s2, s3) {
            console.log(s1); // s1 is 1					//2.2.或者当其中有一个延迟对象被拒绝(rejected)时
            console.log(s2); // s2 is 2
            console.log(s3); // s3 is 3
        });
		
		//d1.reject();				//2.1 或者当其中有一个延迟对象被拒绝(rejected)时
        d1.resolve();				//3.如果“宿主” Deferred(延迟)对象是(resolved)解决状态时
        d2.resolve("abc");
        d3.resolve(1, 2, 3, 4, 5);	//1.当所有的延迟对象被解决(resolve)时

$.When的应用

任何一个操作----不管是ajax操作还是本地操作,也不管是异步操作还是同步操作----都可以使用deferred对象的各种方法,指定回调函数。

我们来看一个具体的例子。假定有一个很耗时的操作wait:

        var wait = function () {

            var tasks = function () {

                console.log("执行完毕!");

            };

            setTimeout(tasks, 5000);

        };
        $.when(wait())

            .done(function () { console.log("哈哈,成功了!"); })  //立即执行

            .fail(function () { console.log("出错啦!"); });

//输出:
哈哈,成功了!
(过5秒)
执行完毕!

$.when()的参数只能是deferred对象

但是,这样写的话,done()方法会立即执行,起不到回调函数的作用。原因在于$.when()的参数只能是deferred对象,所以必须对wait()进行改写:

       var dtd = $.Deferred(); // 新建一个deferred对象
        var wait = function (dtd) {

            var tasks = function () {

                console.log("执行完毕!");
                dtd.resolve(); // 改变deferred对象的执行状态
            };

            setTimeout(tasks, 5000);
            return dtd;     //返回这里deferred对象
        };
        $.when(wait(dtd))

            .done(function () { console.log("哈哈,成功了!"); })

            .fail(function () { console.log("出错啦!"); });
//输出:
(过5秒)
执行完毕!
哈哈,成功了!

wait()函数运行完,就会自动运行done()方法指定的回调函数。

4.deferred.resolve()方法和deferred.reject()方法

deferred对象有三种执行状态----未完成,已完成和已失败。如果执行状态是"已完成"(resolved),deferred对象立刻调用done()方法指定的回调函数;如果执行状态是"已失败",调用fail()方法指定的回调函数;如果执行状态是"未完成",则继续等待,或者调用progress()方法指定的回调函数(jQuery1.7版本添加)。

5.deferred.promise()方法

jQuery提供的deferred.promise()方法的作用是,在原来的Deferred 对象上返回另一个 Deferred 对象,即受限制的 Promise 对象,受限制的 Promise 对象只开放与改变执行状态无关的方法(比如done()方法和fail()方法),屏蔽与改变执行状态有关的方法(比如resolve()方法和reject()方法),从而使得执行状态不能被改变。

前面的例子dtd是一个全局对象,所以它的执行状态可以从外部改变。

 var wait = function (dtd) {

            var tasks = function () {

                console.log("执行完毕!");
                dtd.resolve(); 
            };

            setTimeout(tasks, 5000);
            return dtd;     
        };
        $.when(wait(dtd))

            .done(function () { console.log("哈哈,成功了!"); })

            .fail(function () { console.log("出错啦!"); });

            dtd.resolve(); // 这里改变状态后,直接就执行done了
    //输出:
哈哈,成功了!
(过5秒)
执行完毕!

为了避免这种情况,jQuery提供了deferred.promise()方法。屏蔽与改变执行状态有关的方法(比如resolve()方法和reject()方法)

       var dtd = $.Deferred(); 
        var wait = function (dtd) {

            var tasks = function () {

                console.log("执行完毕!");
                dtd.resolve(); 
            };

            setTimeout(tasks, 5000);
            return dtd.promise();     //返回这里promise对象
        };


        var d = wait(dtd); 
        $.when(d)

            .done(function () { console.log("哈哈,成功了!"); })

            .fail(function () { console.log("出错啦!"); });

            d.resolve(); // //d 是一个 promise对象,没有resolve方法. 此时,这个语句是无效的

jQuery的deferred对象解析

更好的方法是

        var wait = function (dtd) {
            var dtd = $.Deferred();  //在函数内部,新建一个Deferred对象
            var tasks = function () {

                console.log("执行完毕!");
                dtd.resolve(); 
            };

            setTimeout(tasks, 5000);
            return dtd.promise();     //返回这里promise对象
        };

        $.when(wait())

            .done(function () { console.log("哈哈,成功了!"); })

            .fail(function () { console.log("出错啦!"); });

6.另外一种写法,deferred对象的建构函数$.Deferred()(一般用第1种)

另一种防止执行状态被外部改变的方法,是使用deferred对象的建构函数$.Deferred()。

这时,wait函数还是保持不变,我们直接把它传入$.Deferred():

$.Deferred(wait)

  .done(function(){ alert("哈哈,成功了!"); })

  .fail(function(){ alert("出错啦!"); });

jQuery规定,$.Deferred()可以接受一个函数名(注意,是函数名)作为参数,$.Deferred()所生成的deferred对象将作为这个函数的默认参数。

7.普通操作的回调函数接口(下):第3种写法(一般用第1种)

除了上面两种方法以外,我们还可以直接在wait对象上部署deferred接口。

  var dtd = $.Deferred(); 

  var wait = function(dtd){

    var tasks = function(){

      alert("执行完毕!");

      dtd.resolve(); 

    };

    setTimeout(tasks,5000);

  };

  dtd.promise(wait); //重点,wait对象上部署Deferred接口,直接调用done和fail

  wait.done(function(){ alert("哈哈,成功了!"); })

  .fail(function(){ alert("出错啦!"); });

  wait(dtd);

这里的关键是dtd.promise(wait)这一行,它的作用就是在wait对象上部署Deferred接口。正是因为有了这一行,后面才能直接在wait上面调用done()和fail()。

8.deferred.then() 快捷写法

有时为了省事,可以把done()和fail()合在一起写,这就是then()方法。

    $.when($.ajax( "/main.php" ))

    .then(successFunc, failureFunc );

如果then()有两个参数,那么第一个参数是done()方法的回调函数,第二个参数是fail()方法的回调方法。如果then()只有一个参数,那么等同于done()。

9. Durandal 实例

self.loadContryList = function (num) {
                       //system.defer 可以替换成 jquery 的 $.Deferred
                return system.defer(function (dfd) {
                    membershipVAT.getAllCountryList().done(function (xhr) {
                        setTimeout(function () { console.log(num); }, 3000);
                        return dfd.resolve(true);
                    }).fail(function (xhr) {
                        return dfd.resolve(false);
                    })
                }).promise();
            }

 var der = self.loadContryList(1);
                der.then(function (xhr) {
                        console.log('aaaaaaaaaaaaaaaa');
                       return self.loadContryList(2);
                    }).then(function (data) {
                        return self.loadContryList(3);
                    }).then(function (data) {
                        return  self.loadContryList(4);
                    });

jQuery的deferred对象详解:http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html

相关文章:

  • 2021-12-25
猜你喜欢
  • 2022-02-16
  • 2022-12-23
  • 2022-12-23
  • 2021-05-15
相关资源
相似解决方案