2012 08 May jQuery全面解剖系列(一)Deferred风格的Ajax

先宣佈一件事:考慮到正體字在華人世界中通行度更高,以後本站全部改用正體字, 如遇到中國和港臺在稱呼上有衝突的計算機詞彙一律使用英文代替。

最近准備寫一個系列的文章來談jQuery的種種技巧和原理。

今天講Deferred風格的Ajax,本篇分爲兩部分,第一部分介紹Deferred風格的Ajax的基本使用,第二部分深入一點介紹原理。

基本使用

Deferred是jQuery1.5加入的特性,可以把延遲函數寫成鏈式的樣子,開發更加方便和靈活些。

先來看一個例子:

$.ajax('/test.html').done(function(html) {
    console.log(html);
});

這是deferred在Ajax中的典型應用,這段代碼的意思是說請求一個Ajax請求,待請求完成的時候執行一個函數,將結果打印出來。

在1.5以前,我們是這樣實現的:

$.ajax({url: '/test.html', success: function(html) {
    console.log(html);
}});

下面我們給一個對照表

參數參數Deferred函數觸發事件
successsuccess/done請求成功
errorerror/fail請求失敗
completecomplete/always請求成功 & 失敗

深入解析

Deferred object

要說清楚這裡面的原理,我們不得不窺探一下$.Deferred object了。

先來看一個簡單的例子:

var d = $.Deferred();
d.done(function() {
    console.log('Done');
});
console.log('1 - ' + d.state());
d.resolve();
console.log('2 - ' + d.state());

執行結果:

1 - pending
Done
2 - resolved

從這裡我們可以看到以下幾點:

  1. $.Deferred object是有狀態的
  2. 注冊一個done函數之後,並不會立即被執行
  3. relove可以修改d的狀態
  4. 狀態發生變化的時候會調用之前注册的done函數

我們再看一例:

var d = $.Deferred();
d.fail(function() {
    console.log('Failed');
});
d.always(function() {
    console.log('Completed');
});
console.log('1 - ' + d.state());
d.reject();
console.log('2 - ' + d.state());
d.resolve();
console.log('3 - ' + d.state());

執行結果:

1 - pending
Failed
Completed
2 - rejected
3 - rejected

always就是不管成功還是失敗總是執行,而且在done/fail函數之後執行。另外我們先把狀態改成了rejected,再調用resolve就無效了。

我們調整一下調用順序看看會怎樣:

var d = $.Deferred();
console.log('1 - ' + d.state());
d.reject();
console.log('2 - ' + d.state());
d.fail(function() {
    console.log('Failed');
});

執行結果:

1 - pending
2 - rejected
Failed

我們先改狀態,後注冊fail函數,fail函數還是執行了

再把always加進去看看會發生什麼

var d = $.Deferred();
d.always(function() {
    console.log('Completed');
});
console.log('1 - ' + d.state());
d.reject();
console.log('2 - ' + d.state());
d.fail(function() {
    console.log('Failed');
});

執行結果:

1 - pending
Completed
2 - rejected
Failed

沒有done & fail的時候,always就不會傻等了,自己直接先執行了。

總結幾點好了:

  1. 内部維護一個狀態,外部可以通過reslove/reject來改變之。
  2. 狀態發生變化的時候會調用相應的方法,當然如果没有就算了。
  3. 給 object注册方法的時候,如果狀態已經變化至此,會立即執行的。
  4. 狀態一旦發生變化就不能再改變了,就是說不能這樣pedding->resolved->rejected。

好了,了了這些$.Deferred的相關内容,我們再來看看實際的場合會怎樣用這個咚咚吧。

function longTimeJob() {
    var deferred = $.Deferred();
    // do something
    setTimeout(function() {
    // Complete job
        if (new Date().getTime() % 2) {
            console.log("My job done");
            deferred.resolve();
        } else {
            console.log("My job failed");
            deferred.reject();
        }
    }, 3000);
    return deferred;
}

longTimeJob().done(function() {
    console.log('Done');
}).fail(function() {
    console.log('Failed');
}).always(function() {
    console.log('Completed');
});

執行結果:

My job failed
Failed
Completed

longTimeJob是一個需要3秒以上才能完成的任務,但函數會立即返回,狀態的改變是異步的,感覺像是多線程的,所以我們可以調用完之後立即注册done/fail/always函數,這樣當job的狀態發生變化的時候就會調用我們此前注册的函數。

看到這裡再回想一下文章最開始處給出的Ajax的例子,是不是有幾分相似呢?其實呢,原理是一樣的啦。ajax同樣是一個耗時的工作,但會立即返回(除非你指定了async爲false)。

其實呢,ajax的返回值和我們這裡的longTimeJob還是有區别的,而是一個Promise和XMLHTTPRequest綜合體。Promise可以理解爲是一個只讀版的$.Deferred object,没有reject/resolve,其他都一樣。同時該 object還有一些操作XMLHTTPRequest object的功能,比如getResponseHeader什麽的,請看下圖。 ajax函數返回值

獲得Promise object的方法很簡單,$.Deferred().promise()就可以了。

完。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值