对比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对象由于用处不大,我始终没有系统的学习,只是在jQuery.ajax里面间接使用过。到今天,虽然ES6和Vue等新技术很有市场,但是jQuery依然是小型项目的最佳解决方案,更何况我们开发PC页面依然必须支持IE8,我的项目也越写越复杂,所以我认为jQuery.defered对象是IE8中解决回调问题的优选之一。另一套技术方案就是用Promise的polyfill,它的优点是跟原生Promise的语法完全一致,缺点是要专门引入库。

本文只对比两种技术方案的区别,适合于已经熟悉原生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("执行完毕1");
        deferred.resolve(1);
  },4000);
    return deferred;
};

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

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

这个方法的正确使用姿势是:传入0个或者多个延迟对象。当全部成功,则执行.done,如果有一个失败,就执行.fail。

在多个延迟对象传递给jQuery.when() 的情况下,.when()根据一个新的“宿主” Deferred(延迟)对象,跟踪所有已通过Deferreds聚集状态,返回一个Promise对象。

当所有的延迟对象被解决(resolve)时,“宿主” Deferred(延迟)对象才会解决(resolved)该方法,或者当其中有一个延迟对象被拒绝(rejected)时,“宿主” Deferred(延迟)对象就会reject(拒绝)该方法。

如果“宿主” Deferred(延迟)对象是解决(resolved)状态时, “宿主” Deferred(延迟)对象的 doneCallbacks (解决回调)将被执行。参数传递给 doneCallbacks提供这解决(resolved)值给每个对应的Deferreds对象,并匹配Deferreds传递给 jQuery.when()的顺序。

再看看构造延迟对象的区别

从书写上,两个例子略有区别,jq的写法是以普通函数return延迟对象,原生写法是用构造函数直接构造延迟对象。那么jq有没有直接构造延迟对象的办法?有。

下面就是以构造函数$.Deferred()直接构造延迟对象的例子,构造函数会给回调函数的参数传入一个空延迟对象,所以内部不需要var deferred = $.Deferred();。then里的代码完全相同。

$.Deferred(function(dfd){
    setTimeout(function(){
        console.log("1执行完毕!");
        dfd.resolve(1);
    },4000);
    return dfd;
})
.then(function(value){
    var deferred = $.Deferred();
    setTimeout(function(){
        console.log("2执行完毕!");
        deferred.resolve(value + 1);
    },3000);
    return deferred;
})
.then(function(value){
    var deferred = $.Deferred();
    setTimeout(function(){
        console.log("3执行完毕!" + value);
        deferred.resolve();
    },2000);
    return deferred;
});

这两种的代码量、理解难易度都差不多,如果你的“第一步操作”只需要创建一个延迟对象,那么用谁都可以,如果你的“第一步操作”需要创建多个延迟对象,而且这些延迟操作是并发关系,那么只能用$.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中唯一可以传递延迟状态的方法。其实在1.8版本之前,没有任何方法可以传递延迟状态,只不过1.8版本开始,jQ的开发者们给then赋予了传递延迟状态的能力,这时候,很多使用者误以为done和fail等也可以传递延迟状态,其实并不是,记住,直至本文完稿为止,只有then方法有这个能力。

再具体说,就是then方法后面可以接done、fail等方法,then可以把延迟状态传递给done和fail等方法,但是,done、fail方法后面不可以接then方法,说白了done、fail就是延迟链的终点,不会再有延迟对象传递。这跟原生Promises是不一样的。

deferred.done也没有对应任何原生Promise方法,千万不要以为deferred.done对应单参数的new Promise().then,因为deferred.done连缀书写的话,各个回调函数是并列关系,回调函数里面如果有异步任务,会导致执行顺序不符合你的期待。

deferred.fail跟deferred.done同理,不要以为deferred.fail对应new Promise().catch。而且,new Promise().catch后面可以继续传递延迟状态,但是deferred.fail不可以。

看了上文,你就也可以知道,deferred.catch也不对应new Promise().catch。deferred.catch是deferred.then( null, fn )的别名,deferred.catch跟deferred.fail的区别在于deferred.fail更强大,可以接受多个函数。

deferred.always也没有对应方法,因为always可以传入处理程序列表,但是这些处理程序是同类并列关系,并不是说前一个函数对应成功,后一个函数对应失败。所以jQuery官方也建议,不要去用if判断上一步到底是成功还是失败,而是应当执行一些无状态的语句,这样才符合always单词的语义。如果想判断,依然推荐你用done和fail。

$.when()对应Promise.all()

没有方法对应Promise.race()

剩余其他deferred方法用得少,暂不举例

现在就可以看出来各方的优势了,原生方法的优势是符合业界标准,理解简单,jQ的优势是除了没有Promise.race(),其他方法很多。所以,技术选型时:

  • 如果你确定不需要Promise.race()功能,但很需要jQ自带的一些方法全部方法看这里,那么,选jQuery.defered。

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容

  • 请移步: https://blog.cdswyda.com/post/20160923
    依韵宵音阅读 392评论 0 6
  • Promise 的含义 一句话概括一下promise的作用:可以将异步操作以同步操作的流程表达出来,避免了层层嵌套...
    雪萌萌萌阅读 5,483评论 0 7
  • JQuery 中利用 Deferred 对象提供类似 ES2016(aka. es7) 中 Promise 的功能...
    鳳歌阅读 482评论 0 2
  • 加油好姑娘,没有白白付出的辛酸与泪水,坚定信念,永不放弃,天道酬勤! 52分钟前 这是我在刚看的微信留言里,复制的...
    翩翩的精灵女侠阅读 198评论 0 0
  • 时光飞逝,一转眼五月就进入尾声,我成为007-9班首月志愿者的日子也即将结束了。今天,我即将竞选6月的值月生,在回...
    欣兴妈妈阅读 158评论 0 2