對比jQuery.defered對象和原生Promise對象

參考文章:
jQuery的deferred對象詳解以及我寫過的Promise文章
jQuery.defered最新的文檔:http://www.css88.com/jqapi-1.9/category/deferred-object/

前言

jQuery跟人的第一印象就是操作DOM的庫缺厉,新手學習jQuery也是先從操作DOM學起,我當年也是如此。學會了操作DOM之后再學學事件和Ajax蝶防,就以為學成了缤灵,然而jQuery.defered對象由于用處不大妒御,我始終沒有系統(tǒng)的學習佩厚,只是在jQuery.ajax里面間接使用過蚊惯。到今天辆床,雖然ES6和Vue等新技術很有市場佳晶,但是jQuery依然是小型項目的最佳解決方案,更何況我們開發(fā)PC頁面依然必須支持IE8讼载,我的項目也越寫越復雜轿秧,所以我認為jQuery.defered對象是IE8中解決回調問題的優(yōu)選之一。另一套技術方案就是用Promise的polyfill咨堤,它的優(yōu)點是跟原生Promise的語法完全一致菇篡,缺點是要專門引入庫。

本文只對比兩種技術方案的區(qū)別一喘,適合于已經熟悉原生Promise理念驱还,也研究過jQuery.defered對象的人閱讀。

鏈式操作舉例

找出我從前的一個例子(原文)凸克,隔一段時間打印一些字符议蟆。原生寫法如下:

var promise = new Promise(function(resolve, reject) {
    setTimeout(function() {
        console.log('第一個回調');
        resolve(3);
    }, 3000);
});

promise.then(function(value) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log('第二個回調');
            console.log(value * 2);
            resolve(value * 2);
        }, 2000);
    });
}).then(function(value) {
    setTimeout(function() {
        console.log('第三個回調');
        console.log(value * 2);
    }, 1000);
});

也就是先new一個Promise對象,然后在這個Promise對象身上加then方法萎战。

jQuery.defered()方案寫法如下:

var dfd = function() {
    var deferred = $.Deferred();
    setTimeout(function() {
        console.log("執(zhí)行完畢1");
        deferred.resolve(1);
  },4000);
    return deferred;
};

$.when(dfd())
.then(function(value){
    var deferred = $.Deferred();
    setTimeout(function() {
        console.log("執(zhí)行完畢2");
        console.log('value = ' + value);
        deferred.resolve(value + 1);
    },3000);
    return deferred;
})
.then(function(value){
    var deferred = $.Deferred();
    setTimeout(function() {
        console.log("執(zhí)行完畢3");
        console.log('value = ' + value);
        deferred.resolve(value + 1);
    },2000);
    return deferred;
});

首先研究一下$.when()(文檔

這個方法的正確使用姿勢是:傳入0個或者多個延遲對象咐容。當全部成功,則執(zhí)行.done蚂维,如果有一個失敗疟丙,就執(zhí)行.fail颖侄。

在多個延遲對象傳遞給jQuery.when() 的情況下,.when()根據一個新的“宿主” Deferred(延遲)對象享郊,跟蹤所有已通過Deferreds聚集狀態(tài)览祖,返回一個Promise對象。

當所有的延遲對象被解決(resolve)時炊琉,“宿主” Deferred(延遲)對象才會解決(resolved)該方法展蒂,或者當其中有一個延遲對象被拒絕(rejected)時,“宿主” Deferred(延遲)對象就會reject(拒絕)該方法苔咪。

如果“宿主” Deferred(延遲)對象是解決(resolved)狀態(tài)時锰悼, “宿主” Deferred(延遲)對象的 doneCallbacks (解決回調)將被執(zhí)行。參數傳遞給 doneCallbacks提供這解決(resolved)值給每個對應的Deferreds對象团赏,并匹配Deferreds傳遞給 jQuery.when()的順序箕般。

再看看構造延遲對象的區(qū)別

從書寫上,兩個例子略有區(qū)別舔清,jq的寫法是以普通函數return延遲對象丝里,原生寫法是用構造函數直接構造延遲對象。那么jq有沒有直接構造延遲對象的辦法体谒?有杯聚。

下面就是以構造函數$.Deferred()直接構造延遲對象的例子,構造函數會給回調函數的參數傳入一個空延遲對象抒痒,所以內部不需要var deferred = $.Deferred();幌绍。then里的代碼完全相同。

$.Deferred(function(dfd){
    setTimeout(function(){
        console.log("1執(zhí)行完畢故响!");
        dfd.resolve(1);
    },4000);
    return dfd;
})
.then(function(value){
    var deferred = $.Deferred();
    setTimeout(function(){
        console.log("2執(zhí)行完畢傀广!");
        deferred.resolve(value + 1);
    },3000);
    return deferred;
})
.then(function(value){
    var deferred = $.Deferred();
    setTimeout(function(){
        console.log("3執(zhí)行完畢!" + value);
        deferred.resolve();
    },2000);
    return deferred;
});

這兩種的代碼量彩届、理解難易度都差不多主儡,如果你的“第一步操作”只需要創(chuàng)建一個延遲對象,那么用誰都可以惨缆,如果你的“第一步操作”需要創(chuàng)建多個延遲對象糜值,而且這些延遲操作是并發(fā)關系,那么只能用$.when()坯墨,因為它可以接受多個延遲對象寂汇,且會更待所有的操作完成再做出響應。

jQuery.defered對象和原生Promise對象對應關系總結

以下左為jQuery.defered對象捣染,右為原生Promise對象

$.Deferred()類似于new Promise()

deferred.then沒有對應任何原生Promise方法骄瓣,因為deferred.then可以有三個處理程序,第一個是成功后的耍攘,第二個是失敗后的榕栏,第三個是[可選]當Deferred(延遲)對象生成進度通知時被調用的一個函數畔勤。也就是說,deferred.then = deferred.done + deferred.fail + progressFilter扒磁。

deferred.then是jQuery中唯一可以傳遞延遲狀態(tài)的方法庆揪。其實在1.8版本之前,沒有任何方法可以傳遞延遲狀態(tài)妨托,只不過1.8版本開始缸榛,jQ的開發(fā)者們給then賦予了傳遞延遲狀態(tài)的能力,這時候兰伤,很多使用者誤以為done和fail等也可以傳遞延遲狀態(tài)内颗,其實并不是,記住敦腔,直至本文完稿為止均澳,只有then方法有這個能力。

再具體說符衔,就是then方法后面可以接done找前、fail等方法,then可以把延遲狀態(tài)傳遞給done和fail等方法柏腻,但是纸厉,done系吭、fail方法后面不可以接then方法五嫂,說白了done、fail就是延遲鏈的終點肯尺,不會再有延遲對象傳遞沃缘。這跟原生Promises是不一樣的。

deferred.done也沒有對應任何原生Promise方法则吟,千萬不要以為deferred.done對應單參數的new Promise().then槐臀,因為deferred.done連綴書寫的話,各個回調函數是并列關系氓仲,回調函數里面如果有異步任務水慨,會導致執(zhí)行順序不符合你的期待。

deferred.fail跟deferred.done同理敬扛,不要以為deferred.fail對應new Promise().catch晰洒。而且,new Promise().catch后面可以繼續(xù)傳遞延遲狀態(tài)啥箭,但是deferred.fail不可以谍珊。

看了上文,你就也可以知道急侥,deferred.catch也不對應new Promise().catch砌滞。deferred.catch是deferred.then( null, fn )的別名侮邀,deferred.catch跟deferred.fail的區(qū)別在于deferred.fail更強大,可以接受多個函數贝润。

deferred.always也沒有對應方法绊茧,因為always可以傳入處理程序列表,但是這些處理程序是同類并列關系题暖,并不是說前一個函數對應成功按傅,后一個函數對應失敗。所以jQuery官方也建議胧卤,不要去用if判斷上一步到底是成功還是失敗唯绍,而是應當執(zhí)行一些無狀態(tài)的語句,這樣才符合always單詞的語義枝誊。如果想判斷诚纸,依然推薦你用done和fail翁逞。

$.when()對應Promise.all()

沒有方法對應Promise.race()

剩余其他deferred方法用得少,暫不舉例

現(xiàn)在就可以看出來各方的優(yōu)勢了,原生方法的優(yōu)勢是符合業(yè)界標準缚俏,理解簡單,jQ的優(yōu)勢是除了沒有Promise.race()耀石,其他方法很多力崇。所以,技術選型時:

  • 如果你確定不需要Promise.race()功能古瓤,但很需要jQ自帶的一些方法全部方法看這里止剖,那么,選jQuery.defered落君。

  • 如果你很需要Promise.race()功能穿香,并不需要jQ自帶的一系列方法,那么用Promise的polyfill绎速,或原生Promise即可皮获。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纹冤,隨后出現(xiàn)的幾起案子洒宝,更是在濱河造成了極大的恐慌,老刑警劉巖萌京,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雁歌,死亡現(xiàn)場離奇詭異,居然都是意外死亡枫夺,警方通過查閱死者的電腦和手機将宪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人较坛,你說我怎么就攤上這事印蔗。” “怎么了丑勤?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵华嘹,是天一觀的道長。 經常有香客問我法竞,道長耙厚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任岔霸,我火速辦了婚禮薛躬,結果婚禮上,老公的妹妹穿的比我還像新娘呆细。我一直安慰自己型宝,他們只是感情好,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布絮爷。 她就那樣靜靜地躺著趴酣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坑夯。 梳的紋絲不亂的頭發(fā)上岖寞,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機與錄音柜蜈,去河邊找鬼仗谆。 笑死,一個胖子當著我的面吹牛跨释,可吹牛的內容都是我干的胸私。 我是一名探鬼主播厌处,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼鳖谈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了阔涉?” 一聲冷哼從身側響起缆娃,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瑰排,沒想到半個月后贯要,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡椭住,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年崇渗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡宅广,死狀恐怖葫掉,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情跟狱,我是刑警寧澤俭厚,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站驶臊,受9級特大地震影響挪挤,放射性物質發(fā)生泄漏。R本人自食惡果不足惜关翎,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一扛门、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纵寝,春花似錦尖飞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至闹啦,卻和暖如春沮明,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背窍奋。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工荐健, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人琳袄。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓江场,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窖逗。 傳聞我的和親對象是個殘疾皇子址否,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內容

  • 請移步: https://blog.cdswyda.com/post/20160923
    依韻宵音閱讀 392評論 0 6
  • Promise 的含義 一句話概括一下promise的作用:可以將異步操作以同步操作的流程表達出來,避免了層層嵌套...
    雪萌萌萌閱讀 5,490評論 0 7
  • JQuery 中利用 Deferred 對象提供類似 ES2016(aka. es7) 中 Promise 的功能...
    鳳歌閱讀 484評論 0 2
  • 加油好姑娘碎紊,沒有白白付出的辛酸與淚水佑附,堅定信念,永不放棄仗考,天道酬勤音同! 52分鐘前 這是我在剛看的微信留言里,復制的...
    翩翩的精靈女俠閱讀 199評論 0 0
  • 時光飛逝秃嗜,一轉眼五月就進入尾聲权均,我成為007-9班首月志愿者的日子也即將結束了顿膨。今天,我即將競選6月的值月生叽赊,在回...
    欣興媽媽閱讀 160評論 0 2