最近準備寫一個系列的文章來談jQuery的種種技巧和原理。 html
今天講Deferred風格的Ajax,本篇分爲兩部分,第一部分介紹Deferred風格的Ajax的基本使用,第二部分深刻一點介紹原理。 ajax
Deferred是jQuery1.5加入的特性,能夠把延遲函數寫成鏈式的樣子,開發更加方便和靈活些。 promise
先來看一個例子: async
$.ajax('/test.html').done(function(html) { console.log(html); });
這是deferred在Ajax中的典型應用,這段代碼的意思是說請求一個Ajax請求,待請求完成的時候執行一個函數,將結果打印出來。 url
在1.5之前,我們是這樣實現的: spa
$.ajax({url: '/test.html', success: function(html) { console.log(html); }});下面我們給一個對照表:
參數 |
Deferred函數 |
觸發事件 |
success |
success/done |
請求成功 |
error |
error/fail |
請求失敗 |
complete |
complete/always |
請求成功&失敗 |
要說清楚這裡面的原理,我們不得不窺探一下$.Deferred object了。 .net
先來看一個簡單的例子: code
var d = $.Deferred(); d.done(function() { console.log('Done'); }); console.log('1 - ' + d.state()); d.resolve(); console.log('2 - ' + d.state());
執行結果: htm
1 - pending Done 2 - resolved
從這裡我們能夠看到如下幾點:
事件
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 - rejectedalways就是無論成功還是失敗總是執行,並且在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就不會傻等了,本身直接先執行了。
總結幾點好了:
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什麼的,請看下圖。
獲得Promise object的方法很簡單,$.Deferred().promise()就能夠了。
完。
擴展閱讀 : 初識 jQuery Deferred