天行健, 君子以自强不息
Sunny's Blog
Title

jQuery的deferred对象学习

jQuery的deferred这个知识点绝对学晚了,想一想可能是在2014年的时候就有听到,但是一直没有用在项目中,多亏了最近我的同事wayne讲了一节basic jquery,我才真正意识到这个问题,所以要赶紧抓过来学学

什么是deferred对象?

deferred对象就是jQuery的回调函数解决方案,在英语中,defer的意思是"延迟",所以deferred对象的含义就是"延迟"到未来某个点再执行。它解决了如何处理耗时操作的问题,对那些操作提供了更好的控制,以及统一的编程接口。

优势1: ajax操作的链式写法

$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery,返回的是XHR对象,你没法进行链式操作;如果高于1.5.0版本,返回的是deferred对象,可以进行链式操作。

                    //采用链式写法以后,代码的可读性大大提高。
                    $.ajax({
                        url: './fake/test.json',
                        type: 'POST',
                        dataType: 'json',
                        data: {param1: 'value1'},
                    })
                    .done(function(data) {
                        console.log(data);
                        data.test = "ssss";
                    })
                    .fail(function() {
                        console.log("error");
                    })
                    .always(function() {
                        console.log("complete");
                    });
                

优势2: 允许自由添加多个回调函数,并且传参也是顺序的

   
                    $.ajax({
                        url: './fake/test.json',
                        type: 'POST',
                        dataType: 'json',
                        data: {param1: 'value1'},
                    })
                    .done(function(data) {
                        console.log(data);
                        data.test = "ssss";
                    })
                    .fail(function() {
                        console.log("error");
                    })
                    .always(function() {
                        console.log("complete");
                    })
                    .done(function(data) {
                        //这个data中包含了data.test
                        console.log(data);
                    });
                

优势3: 允许为多个事件指定一个回调函数,这是传统写法做不到的

                    // $.when() 为多个操作指定回调函数。
                    $.when(
                        $.ajax({
                            url: './fake/test.json',
                            type: 'POST',
                            dataType: 'json',
                            data: {param1: 'value1'},
                        }),
                        $.ajax({
                            url: './fake/test1.json',
                            type: 'POST',
                            dataType: 'json',
                            data: {param1: 'value1'},
                        })
                    )
                    .done(function(data,data2) {
                        console.log("=============");
                        console.log(data); //test.json
                        console.log(data2); //test1.json
                    });
                

优势4: 从ajax操作扩展到了所有操作

deferred对象的最大优点,就是它把这一套回调函数接口,从ajax操作扩展到了所有操作。也就是说,任何一个操作----不管是ajax操作还是本地操作,也不管是异步操作还是同步操作----都可以使用deferred对象的各种方法,指定回调函数。

                var wait = function(){
                    
                    //在函数内部,新建一个Deferred对象,为的是不想让其他代码能改变 wait 方法内部的deferred对象的状态。
                    //$.Deferred() 生成一个deferred对象

                    var dtd = $.Deferred();

                    var tasks = function(){
                        alert("执行完毕!");

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

                    //前面部分的ajax操作时,deferred对象会根据返回结果,自动改变自身的执行状态;但是,在wait()函数中,这个执行状态必须由程序员手动指定。dtd.resolve()的意思是,将dtd对象的执行状态从"未完成"改为"已完成",从而触发done()方法。
                    //类似的,还存在一个deferred.reject()方法,作用是将dtd对象的执行状态从"未完成"改为"已失败",从而触发fail()方法。

                        dtd.resolve(); // 改变deferred对象的执行状态
                    };
                    setTimeout(tasks,5000);

                    //deferred.promise() 只是阻止其他代码来改变这个 deferred 对象的状态。可以理解成,通过 deferred.promise() 方法返回的 deferred promise 对象,是没有 resolve ,reject, progress , resolveWith, rejectWith , progressWith 这些可以改变状态的方法,你只能使用 done, then ,fail 等方法添加 handler 或者判断状态。
                    //也就是说wait()返回的对象是没有resolve等方法的。

                    return dtd.promise();
                };

                $.when(wait())
                .done(function(){ alert("哈哈,成功了!"); })
                .fail(function(){ alert("出错啦!"); });

                

另外的二个重要方法

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

                    $.when($.ajax( "/main.php" ))
                    .then(successFunc, failureFunc );
                

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

2.deferred.always()

这个方法也是用来指定回调函数的,它的作用是,不管调用的是deferred.resolve()还是deferred.reject(),最后总是执行。

参考文章:

jquery在线手册

jQuery的deferred对象详解

jQuery deferred 对象的 promise 方法

地势坤,君子以厚德载物