jQuery.deferred()详解

/** 请注意 这个代码是结合 阮老师 的博客来实现的.
 * 网址 http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html
 * 如果有不懂的请看 阮老师 的网址
 */

// JQ 1.5 版本之前的 AJAX 方法
/**
 * success : 这是一个成功的回调函数
 * error : 这是一个失败的回调函数
 */
$.ajax({
    type: "get",
    url: "./test1.json",
    data: "",
    dataType: "json",
    success: function(response) {
        console.log(response);
    },
    error: function(err) {
        console.log(err);
    }
});

// JQ 1.5 版本之后的 AJAX 方法
/**
 * done : 这是一个成功的回调函数
 * fail : 这是一个失败的回调函数
 */
// (写法1)
$.ajax('./test1.json').done(function() {
    console.log('成功了 ');
}).fail(function() {
    console.log('失败了');
})

/**
 * then : then 接受两个参数, 一个是成功的回调函数, 一个是失败的回调函数
 *        如果成功了,会调用第一个回调函数, 如果失败了, 会调用第二个回调函数
 */
// (写法2)
$.ajax('./test1.json').then(function() {
    console.log('成功了');
}, function() {
    console.log('失败了');
})

/** 
 * ------------------------------------------------ $.when() ------------------------------------------------------
 * (引入 $.when() )
 * 提供一种方法来执行零个或多个( Thenable \ then \ Deferred ) 对象的回调函数,通常是表示异步事件
 * 如果没有参数传递给 jQuery.when(),它会返回一个resolved状态的Promise。
 * 切记 : 如果传参数 那么 他将永远返回的是 成功 的状态, 失败定义的回调函数, 永远不会被执行, 因为不会遭到拒绝
 * 如果传参是 不是一个 Deferred 或 Promise 对象, 那么他将永远返回的是 成功 的状态, 失败定义的回调函数, 永远不会被执行, 因为不会遭到拒绝
 * 
 * 上面说的两种 都不是 异步对象, 所以会直接返回 成功时的回调
 * 如果说是成功的回调, 我们需要调用方法, done 和 fail 只是定义方法, 并没有调用, 不调用 并不会执行!!!
 * resolve() : 这是调用成功的回调, 也就是说 定义的 done 的回调
 * reject() : 这是调用失败的回调, 也就是说 定义的 fail 的回调
 * 如果定义了 两个回调, 并且也执行了 resolve 和 reject, 只会执行最先执行的方法.
 * 如果定义了 成功的 回调, 却执行了 reject 方法, 那么并不会执行,  因为你没有定义方法
 */

$.when().done(function() {
    console.log('成功了'); /** 成功了 */
}).fail(function() {
    console.log('失败了');
})

$.when({ testing: 123 }).done(
    function(x) { alert(x.testing); } /* alerts "123" */
);

var dtd = $.Deferred()
$.when(dtd).done(function() {
    console.log('1111');
}).fail(function() {
    console.log('2222');
})
dtd.resolve() // 111
dtd.reject() // 不会执行,因为并没有定义失败的回调

/**
 * $.when(参数1, 参数2, 参数3...)
 * 此方法接受多个参数, 但是返回的结果却是不一样的, 但是无非还是两种状态, 一种成功时的状态, 一种失败时的状态
 * 成功时的状态 : 必须所有的对象都返回成功, 才会返回成功的回调函数
 * 失败时的状态 : 如果其中只要有一个返回失败, 都会返回失败的回调函数
 * 如果定义函数的时候给了参数, 调用函数的时候没给参数, 那么值将会是 undefined
 */

/** d1, d2 时定义了两个 异步 对象 */
var d1 = $.Deferred();
var d2 = $.Deferred();
/** 调用 when 方法, 并且设置 ( 此处只是设置或者说定义, 并不是调用 ) 成功的回调*/
$.when().done(function(v1, v2) {
    console.log(v1); // "Fish"
    console.log(v2); // "Pizza"
});
/** 调用成功时的方法 */
d1.resolve("Fish");
d2.resolve("Pizza");

/** 传入多个参数的方法 */
var d1 = $.Deferred();
var d2 = $.Deferred();
var d3 = $.Deferred();
var d4 = $.Deferred();
var d5 = $.Deferred();
/** 调用 when 方法, 并且设置 ( 此处只是设置或者说定义, 并不是调用 ) 成功的回调*/
$.when(d1, d2, d3, d4, d5).done(function(v1, v2, v3, v4, v5) {
    console.log(v1); // "Fish"
    console.log(v2); // "Pizza"
    console.log(v3); // undefined
    console.log(v4); // is Array  [1, 2, 3]
    console.log(v5); // is Object {a: "a"}
});
/** 调用成功时的方法 */
d1.resolve("Fish");
d2.resolve("Pizza");
d3.resolve();
d4.resolve(1, 2, 3);
d5.resolve({ a: "a" });

/** ----------------------------------------------------------------------------------------------------------- */

/**
 * 定义一个很耗时的 wait 函数
 * 这个地方不调用 resolve 就可以执行, 是因为 wait 并不是一个 promise 或者 deferred 
 * done()方法会立即执行,起不到回调函数的作用
 * $.when()的参数只能是deferred对象,所以必须对wait()进行改写
 */
var wait = function() {
    var tasks = function() {
        console.log('执行完毕');
    }
    setTimeout(tasks, 2000)
}
$.when(wait())
    .done(function() { console.log("哈哈,成功了!"); })
    .fail(function() { console.log("出错啦!"); });

/** 
 * 改写 wait()
 * 再 wait 函数执行完之后, 函数内部调用了成功的方法就会自动运行 done 函数
 * 当然你也可以 调用失败的方法, 只需要把 `dtd.resolve()` 改成 `dtd.reject()` 即可
 * Deferred 是有三个状态的
 * 第一个状态 : 待开始的状态
 * 第二个状态 : 成功时的状态
 * 第三个状态 : 失败时的状态
 */

// 第一种写法(没有封装)
var dtd = $.Deferred() // 创建一个 Deferred 对象
var wait = function(dtd) { // 要求传入一个 deferred 对象, 不然这个函数没有意义了
    var tasks = function() {
        //这里可以有大量的复杂操作
        console.log("执行完毕"); // 执行完毕
        dtd.resolve() // 表示异步任务已经完成, 改变 deferred 对象的状态

        // dtd.reject() // 表示异步任务失败, 改变 deferred 对象的状态
    }
    setTimeout(tasks, 2000) // 等待 2m 后执行
    return dtd // 一定要有返回值, 并且 一定是这个 对象
}
$.when(wait(dtd))
    .done(function() { console.log("哈哈,成功了!"); }) // 哈哈,成功了!
    .fail(function() { console.log("出错啦!"); });

// // 第二种写法 (封装版)
function waitHandle() {
    var dtd = $.Deferred()
    var wait = function(dtd) {
        var tasks = function() {
            console.log('执行完毕') // 执行完毕
            dtd.resolve()

            // dtd.reject()
        }
        setTimeout(tasks, 2000)
        return dtd
    }
    return wait(dtd)
}
var w = waitHandle()

// 此处同样可是使用 then 方法来调用
w.then(function() {
    console.log('ok 1'); // ok 1
}, function() {
    console.log('err 1');
}).then(function() {
    console.log('ok 1'); // ok 1
}, function() {
    console.log('err 1');
})

/**
 * 这样呢 : 有一个弊端就是, 可以手动修改状态.
 * 举梨 : 比如 我们函数中, 定义的是 dtd.resolve() 方法,但是我们再程序的最后一行加上 `w.reject()` 
 * 结果 就很有意思了, 会再程序以执行的时候, 改变 dtd 的状态, 然后立即执行 `done()`, 等到 延时器 结束的时候再执行 `console.log('执行完毕')`
 * 这样就不是我们想要的了
 * 所以 : 就引出了 deferred.promise() 方法.
 */

// + w.resolve()

/** -------------------------------------- deferred.promise() -------------------------------------------------- */

/** 只需要再 wait() 函数里面
 *  return 的不在是`dtd` 而是 return `dtd.promise`
 *  这样我们再外边就没有办法修改了
 *  给大家 将一个 思路
 *  就是说 函数里面的 dtd.resolve 和 dtd.reject 这两个函数是主动触发的
 *  还有就是 w.then() 或者 done 还有 fail 这几个函数是被动监听的
 */

//  第一种方法
function waitHandle() {
    var dtd = $.Deferred()
    var wait = function(dtd) {
        var tasks = function() {
            console.log('执行完毕') // 执行完毕
            dtd.resolve()

            // dtd.reject()
        }
        setTimeout(tasks, 2000)

        // return dtd
        return dtd.promise() // 返回的不再是 dtd 而是 dtd 的 promise 对象.
    }
    return wait(dtd)
}
var w = waitHandle() // 经过上面的修改, 现在 w 接受的就是一个 promise 对象
w.then(function() {
    console.log('ok 1'); // ok 1
}, function() {
    console.log('err 1');
}).then(function() {
    console.log('ok 1'); // ok 1
}, function() {
    console.log('err 1');
})

w.reject() // 而运行这句话的时候会直接报错

// 第二种方法. 可以直接在wait对象上部署deferred接口。
var dtd = $.Deferred(); // 生成Deferred对象
var wait = function(dtd) {
    var tasks = function() {
        console.log("执行完毕!");
        dtd.resolve(); // 改变Deferred对象的执行状态
    };
    setTimeout(tasks, 5000);
};
dtd.promise(wait);
wait.done(function() { console.log("哈哈,成功了!"); })
    .fail(function() { console.log("出错啦!"); });
wait(dtd);

/**
 * 总结 : deferred 对象的方法
 * 1. $.Deferred()          生成一个新的对象
 * 2. deferred.done()       指定操作成功时的回调
 * 3. deferred.fail()       指定操作失败时的回调
 * 4. deferred.promise()    没有参数的时候, 返回一个新的 deferred 对象, 该对象的运行状态无法被改变; 接受参数时, 作用为参数对象对象上部署 deferred 接口
 * 5. deferred.resolve()    手动改变 deferred 对象的运行状态为 "完成" ,从而立即触发 done 或者 then 的第一个回调函数
 * 6. deferred.reject()     手动改变 deferred 对象的运行状态为 "失败" ,从而立即触发 fail 或者 then 的第二个回调函数
 * 7. $.when()              为单个或多个操作指定回调函数
 * 8. deferred.then()       此方法就是把 done 和 fail 方法的合并, 里面有两个参数 第一个时成功时的回调, 第二个时失败时的回调,可以只写一个.
 * 9. deferred.always()     这个方法之前没说过,他的作用是, 不管调用的是 deferred.resolve 还是 deferred.reject, 总是最后才执行
 */
 
$.ajax("test.html")
    .always(function() { alert("已执行!"); });

猜你喜欢

转载自blog.csdn.net/qq_41702660/article/details/84894137
今日推荐