jQuery中的deferred对象和extend方法详解


Posted in jQuery onMay 08, 2017

1 deferred对象

deferred对象是jQuery的回调函数解决方案,它是从jQuery1.5.0版本开始引入的功能

deferred对象的方法

(1) $.Deferred() 生成一个deferred对象。

(2) deferred.done() 指定操作成功时的回调函数

(3) deferred.fail() 指定操作失败时的回调函数

(4) deferred.promise() 没有参数时,返回一个新的deferred对象,该对象的运行状态无法被改变;接受参数时,作用为在参数对象上部署deferred接口。

(5) deferred.resolve() 手动改变deferred对象的运行状态为"已完成",从而立即触发done()方法。

(6)deferred.reject() 这个方法与deferred.resolve()正好相反,调用后将deferred对象的运行状态变为"已失败",从而立即触发fail()方法

(7) $.when() 为多个操作指定回调函数。

除了这些方法以外,deferred对象还有二个重要方法,上面的教程中没有涉及到。

(8)deferred.then()

有时为了省事,可以把done()和fail()合在一起写,这就是then()方法。

$.when($.ajax( "/main.php" ))

.then(successFunc, failureFunc );

如果then()有两个参数,那么第一个参数是done()方法的回调函数,第二个参数是fail()方法的回调方法。如果then()只有一个参数,那么等同于done()。

(9)deferred.always()

这个方法也是用来指定回调函数的,它的作用是,不管调用的是deferred.resolve()还是deferred.reject(),最后总是执行。

$.ajax( "test.html" )
.always( function() { alert("已执行!");} );

来点儿

1)ajax操作的链式写法

先回顾一下jQuery的ajax操作的传统写法:

$.ajax({


url: "test.html",



success: function(){



alert("哈哈,成功了!");


},



error:function(){



alert("出错啦!");


}

});

在上面的代码中,$.ajax()接受一个对象参数,这个对象包含两个方法:success方法指定操作成功后的回调函数,error方法指定操作失败后的回调函数。

$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery,返回的是XHR对象,你没法进行链式操作;如果高于1.5.0版本,返回的是deferred对象,可以进行链式操作。

有了deferred对象之后,可以这样写了

$.ajax("test.html")

.done(function(){ alert("哈哈,成功了!"); })

.fail(function(){ alert("出错啦!"); });

上面代码中的done()相当于success方法,fail()相当于error方法。采用链式写法以后,代码的可读性大大提高。

2)指定同一操作的多个回调函数

deferred对象的一大好处,就是它允许你自由添加多个回调函数。

还是以上面的代码为例,如果ajax操作成功后,除了原来的回调函数,我还想再运行一个回调函数,怎么办?

很简单,直接把它加在后面就行了。

$.ajax("test.html")

.done(function(){ alert("哈哈,成功了!");} )


.fail(function(){ alert("出错啦!"); } )

.done(function(){ alert("第二个回调函数!");} );

回调函数可以添加任意多个,它们按照添加顺序执行。

3)为多个操作指定回调函数

deferred对象的另一大好处,就是它允许你为多个事件指定一个回调函数,这是传统写法做不到的。

请看下面的代码,它用到了一个新的方法$.when():

$.when($.ajax("test1.html"), $.ajax("test2.html"))

.done(function(){ alert("哈哈,成功了!"); })

.fail(function(){ alert("出错啦!"); });

这段代码的意思是,先执行两个操作$.ajax("test1.html")和$.ajax("test2.html"),如果都成功了,就运行done()指定的回调函数;如果有一个失败或都失败了,就执行fail()指定的回调函数。

4)普通操作的回调函数接口(上)

deferred对象的最大优点,就是它把这一套回调函数接口,从ajax操作扩展到了所有操作。也就是说,任何一个操作----不管是ajax操作还是本地操作,也不管是异步操作还是同步操作----都可以使用deferred对象的各种方法,指定回调函数。

我们来看一个具体的例子。假定有一个很耗时的操作wait:

var wait = function(){


var tasks = function(){




alert("执行完毕!");



};



setTimeout(tasks,5000);

};

我们为它指定回调函数,应该怎么做呢?

很自然的,你会想到,可以使用$.when():

$.when(wait())

.done(function(){ alert("哈哈,成功了!"); })

.fail(function(){ alert("出错啦!"); });

但是,这样写的话,done()方法会立即执行,起不到回调函数的作用。原因在于$.when()的参数只能是deferred对象,所以必须对wait()进行改写:

var dtd = $.Deferred(); // 新建一个deferred对象

var wait = function(dtd){



var tasks = function(){




alert("执行完毕!");




dtd.resolve(); // 改变deferred对象的执行状态



};



setTimeout(tasks,5000);



return dtd;

};

现在,wait()函数返回的是deferred对象,这就可以加上链式操作了。

$.when(wait(dtd))

.done(function(){ alert("哈哈,成功了!"); })

.fail(function(){ alert("出错啦!"); });

wait()函数运行完,就会自动运行done()方法指定的回调函数。

5)deferred.resolve()方法和deferred.reject()方法 

jQuery规定,deferred对象有三种执行状态----未完成,已完成和已失败。如果执行状态是"已完成"(resolved),deferred对象立刻调用done()方法指定的回调函数;如果执行状态是"已失败",调用fail()方法指定的回调函数;如果执行状态是"未完成",则继

续等待,或者调用progress()方法指定的回调函数(jQuery1.7版本添加)。

前面部分的ajax操作时,deferred对象会根据返回结果,自动改变自身的执行状态;但是,在wait()函数中,这个执行状态必须由程序员手动指定。dtd.resolve()的意思是,将dtd对象的执行状态从"未完成"改为"已完成",从而触发done()方法。

类似的,还存在一个deferred.reject()方法,作用是将dtd对象的执行状态从"未完成"改为"已失败",从而触发fail()方法。

var dtd = $.Deferred(); // 新建一个Deferred对象

var wait = function(dtd){



var tasks = function(){




alert("执行完毕!");




dtd.reject(); // 改变Deferred对象的执行状态



};



setTimeout(tasks,5000);



return dtd;


};


$.when(wait(dtd))


.done(function(){ alert("哈哈,成功了!"); })
  .fail(function(){ alert("出错啦!"); });

6)deferred.promise()方法

上面这种写法,还是有问题。那就是dtd是一个全局对象,所以它的执行状态可以从外部改变。

请看下面的代码:

var dtd = $.Deferred(); // 新建一个Deferred对象

var wait = function(dtd){



var tasks = function(){




alert("执行完毕!");




dtd.resolve(); // 改变Deferred对象的执行状态



};



setTimeout(tasks,5000);



return dtd;


};


$.when(wait(dtd))


.done(function(){ alert("哈哈,成功了!"); })


.fail(function(){ alert("出错啦!"); });

dtd.resolve();

我在代码的尾部加了一行dtd.resolve(),这就改变了dtd对象的执行状态,因此导致done()方法立刻执行,跳出"哈哈,成功了!"的提示框,等5秒之后再跳出"执行完毕!"的提示框。

为了避免这种情况,jQuery提供了deferred.promise()方法。它的作用是,在原来的deferred对象上返回另一个deferred对象,后者只开放与改变执行状态无关的方法(比如done()方法和fail()方法),屏蔽与改变执行状态有关的方法(比如resolve()方法和

reject()方法),从而使得执行状态不能被改变。

请看下面的代码:

var dtd = $.Deferred(); // 新建一个Deferred对象

var wait = function(dtd){



var tasks = function(){




alert("执行完毕!");




dtd.resolve(); // 改变Deferred对象的执行状态



};



setTimeout(tasks,5000);



return dtd.promise(); // 返回promise对象


};


var d = wait(dtd); // 新建一个d对象,改为对这个对象进行操作


$.when(d)


.done(function(){ alert("哈哈,成功了!"); })


.fail(function(){ alert("出错啦!"); });

d.resolve(); // 此时,这个语句是无效的

在上面的这段代码中,wait()函数返回的是promise对象。然后,我们把回调函数绑定在这个对象上面,而不是原来的deferred对象上面。这样的好处是,无法改变这个对象的执行状态,要想改变执行状态,只能操作原来的deferred对象。

不过,更好的写法是将dtd对象变成wait()函数的内部对象。

var wait = function(dtd){


var dtd = $.Deferred(); //在函数内部,新建一个Deferred对象



var tasks = function(){




alert("执行完毕!");




dtd.resolve(); // 改变Deferred对象的执行状态



};



setTimeout(tasks,5000);



return dtd.promise(); // 返回promise对象


};


$.when(wait())


.done(function(){ alert("哈哈,成功了!"); })

.fail(function(){ alert("出错啦!"); });

7)普通操作的回调函数接口(中)

另一种防止执行状态被外部改变的方法,是使用deferred对象的建构函数$.Deferred()。

这时,wait函数还是保持不变,我们直接把它传入$.Deferred():

$.Deferred(wait)
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });

jQuery规定,$.Deferred()可以接受一个函数名(注意,是函数名)作为参数,$.Deferred()所生成的deferred对象将作为这个函数的默认参数。

8)普通操作的回调函数接口(下)

除了上面两种方法以外,我们还可以直接在wait对象上部署deferred接口。

var dtd = $.Deferred(); // 生成Deferred对象

var wait = function(dtd){



var tasks = function(){




alert("执行完毕!");




dtd.resolve(); // 改变Deferred对象的执行状态



};



setTimeout(tasks,5000);


};


dtd.promise(wait);


wait.done(function(){ alert("哈哈,成功了!"); })


.fail(function(){ alert("出错啦!"); });

wait(dtd);

这里的关键是dtd.promise(wait)这一行,它的作用就是在wait对象上部署Deferred接口。正是因为有了这一行,后面才能直接在wait上面调用done()和fail()。

2 extend方法

JQuery的extend扩展方法:

Jquery的扩展方法extend是我们在写插件的过程中常用的方法,该方法有一些重载原型,在此,我们一起去了解了解。

1)Jquery的扩展方法原型是:

 

extend(dest,src1,src2,src3...);

它的含义是将src1,src2,src3...合并到dest中,返回值为合并后的dest,由此可以看出该方法合并后,是修改了dest的结构的。如果想要得到合并的结果却又不想修改dest的结构,可以如下使用:

var newSrc=$.extend({},src1,src2,src3...)//也就是将"{}"作为dest参数。

这样就可以将src1,src2,src3...进行合并,然后将合并结果返回给newSrc了。如下例:

var result=$.extend({},{name:"Tom",age:21},{name:"Jerry",sex:"Boy"})

那么合并后的结果

result={name:"Jerry",age:21,sex:"Boy"}

也就是说后面的参数如果和前面的参数存在相同的名称,那么后面的会覆盖前面的参数值。

2)省略dest参数

上述的extend方法原型中的dest参数是可以省略的,如果省略了,则该方法就只能有一个src参数,而且是将该src合并到调用extend方法的对象中去,如:

$.extend(src)

该方法就是将src合并到jquery的全局对象中去,如:

$.extend({
hello:function(){alert('hello');}
});

就是将hello方法合并到jquery的全局对象中。

$.fn.extend(src)

该方法将src合并到jquery的实例对象中去,如:

$.fn.extend({
hello:function(){alert('hello');}
});

就是将hello方法合并到jquery的实例对象中。

下面例举几个常用的扩展实例:

$.extend({net:{}});

这是在jquery全局对象中扩展一个net命名空间。

$.extend($.net,{
hello:function(){alert('hello');}
})

这是将hello方法扩展到之前扩展的Jquery的net命名空间中去。

3)Jquery的extend方法还有一个重载原型: 

extend(boolean,dest,src1,src2,src3...)

第一个参数boolean代表是否进行深度拷贝,其余参数和前面介绍的一致,什么叫深层拷贝,我们看一个例子:

var result=$.extend( true, {}, 
{ name: "John", location: {city: "Boston",county:"USA"} }, 
{ last: "Resig", location: {state: "MA",county:"China"} } );

我们可以看出src1中嵌套子对象location:{city:"Boston"},src2中也嵌套子对象location:{state:"MA"},第一个深度拷贝参数为true,那么合并后的结果就是:

result={name:"John",last:"Resig",
location:{city:"Boston",state:"MA",county:"China"}}

也就是说它会将src中的嵌套子对象也进行合并,而如果第一个参数boolean为false,我们看看合并的结果是什么,如下:

var result=$.extend( false, {}, 
{ name: "John", location:{city: "Boston",county:"USA"} }, 
{ last: "Resig", location: {state: "MA",county:"China"} } 
);

那么合并后的结果就是:

result={name:"John",last:"Resig",location:{state:"MA",county:"China"}}

以上是网上看到的两篇分别对jQuery中的deferred对象和extend方法的介绍,感觉比较详细而且容易理解,所以把它们整理到一起与大家分享!

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

jQuery 相关文章推荐
jquery实现提示语淡入效果
May 05 jQuery
jQuery模拟实现天猫购物车动画效果实例代码
May 25 jQuery
Angular2使用jQuery的方法教程
May 28 jQuery
jQuery用户头像裁剪插件cropbox.js使用详解
Jun 07 jQuery
jQuery层级选择器_动力节点节点Java学院整理
Jul 04 jQuery
使用JQuery实现图片轮播效果的实例(推荐)
Oct 24 jQuery
jQuery中库的引用方法
Jan 06 jQuery
jQuery简单判断值是否存在于数组中的方法示例
Apr 17 jQuery
通过JQuery,JQueryUI和Jsplumb实现拖拽模块
Jun 18 jQuery
如何用webpack4.0撸单页/多页脚手架 (jquery, react, vue, typescript)
Jun 18 jQuery
jQuery位置选择器用法实例分析
Jun 28 jQuery
jQuery轮播图功能制作方法详解
Dec 03 jQuery
jQuery中hover方法搭配css的hover选择器,实现选中元素突出显示方法
May 08 #jQuery
jQuery动态追加页面数据以及事件委托详解
May 06 #jQuery
jquery点赞功能实现代码 点个赞吧!
May 29 #jQuery
jQuery extend()详解及简单实例
May 06 #jQuery
jquery仿微信聊天界面
May 06 #jQuery
简单实现jQuery弹幕效果
May 06 #jQuery
jquery实现提示语淡入效果
May 05 #jQuery
You might like
Windows7下PHP开发环境安装配置图文方法
2010/05/20 PHP
ThinkPHP的URL重写问题
2014/06/22 PHP
给WordPress中的留言加上楼层号的PHP代码实例
2015/12/14 PHP
PHP封装mysqli基于面向对象的mysql数据库操作类与用法示例
2019/02/25 PHP
jQuery选择器的工作原理和优化分析
2011/07/25 Javascript
js jquery验证银行卡号信息正则学习
2013/01/21 Javascript
Javascript浅谈之this
2013/12/17 Javascript
详解JS函数重载
2014/12/04 Javascript
使用jquery.form.js实现图片上传的方法
2016/05/05 Javascript
利用jsonp跨域调用百度js实现搜索框智能提示
2016/08/24 Javascript
微信小程序 五星评价功能的实现
2017/03/09 Javascript
微信小程序 图片上传实例详解
2017/05/05 Javascript
react-native之ART绘图方法详解
2017/08/08 Javascript
vue侧边栏动态生成下级菜单的方法
2018/09/07 Javascript
layui-laydate时间日历控件使用方法详解
2018/11/15 Javascript
vue-router传参用法详解
2019/01/19 Javascript
3分钟读懂移动端rem使用方法(推荐)
2019/05/06 Javascript
vue 子组件watch监听不到prop的解决
2020/08/09 Javascript
[02:14]DOTA2英雄基础教程 修补匠
2013/12/23 DOTA
[47:35]VP vs Pain 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/20 DOTA
python 不关闭控制台的实现方法
2011/10/23 Python
wxPython事件驱动实例详解
2014/09/28 Python
Python零基础入门学习之输入与输出
2019/04/03 Python
Python代码使用 Pyftpdlib实现FTP服务器功能
2019/07/22 Python
tensorflow2.0与tensorflow1.0的性能区别介绍
2020/02/07 Python
Antler英国官网:购买安特丽行李箱、拉杆箱
2019/08/25 全球购物
索引覆盖(Index Covering)查询含义
2012/02/18 面试题
公司保密承诺书
2014/03/27 职场文书
临床医师个人自我评价
2014/04/06 职场文书
《风筝》教学反思
2014/04/10 职场文书
青年志愿者活动总结
2014/04/26 职场文书
《闻一多先生的说和做》教学反思
2014/04/28 职场文书
学校百日安全生产活动总结
2014/07/05 职场文书
股东大会通知
2015/04/24 职场文书
2015年中秋放假通知范文
2015/08/18 职场文书
Android开发手册TextInputLayout样式使用示例
2022/06/10 Java/Android