jQuery中的deferred对象和extend方法详解
前端之家收集整理的这篇文章主要介绍了
jQuery中的deferred对象和extend方法详解,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_3010@1 deferred对象
@H
301_0@deferred对象是jQuery的回调
函数解决方案,它是从jQuery1.5.0版本开始引入的
功能
@H_
301_0@<span style="color: #0000ff">
deferred对象的方法
@H_
301_0@(1) $.Deferred()
生成一个deferred对象。
@H_
301_0@(2) deferred.done() 指定操作成功时的回调
函数
@H_
301_0@(3) deferred.fail() 指定操作失败时的回调
函数
@H_
3010@(4) deferred.promise() 没有参数时,返回一个新的deferred对象,该对象的运行状态无法被改变;接受参数时,作用为在参数对象上部署deferred接口。
@H301_0@(5) deferred.resolve() 手动改变deferred对象的运行状态为"已完成",从而立即触发done()
方法。
@H_
301_0@(6)deferred.reject() 这个
方法与deferred.resolve()正好相反,
调用后将deferred对象的运行状态变为"已失败",从而立即触发fail()
方法
@H_
301_0@(7) $.when() 为多个操作指定回调
函数。
@H_
301_0@除了这些
方法以外,deferred对象还有二个重要
方法,上面的教程中没有涉及到。
@H_
3010@(8)deferred.then()
@H301_0@有时为了省事,可以把done()和fail()合在一起写,这就是then()
方法。
<div class="jb51code">
<pre class="brush:js;">
$.when($.ajax( "/main.
PHP" ))
.then(successFunc,failureFunc );
@H_
301_0@如果then()有两个参数,那么第一个参数是done()
方法的回调
函数,第二个参数是fail()
方法的回调
方法。如果then()只有一个参数,那么等同于done()。
@H_
301_0@(9)deferred.always()
@H_
301_0@这个
方法也是用来指定回调
函数的,它的作用是,不管
调用的是deferred.resolve()还是deferred.reject(),最后总是执行。
@H_
301_0@来点儿
@H_
301_0@
1)ajax操作的链式写法
@H_
301_0@先回顾一下jQuery的ajax操作的传统写法:
url: "test.html", success: function(){
alert("哈哈,成功了!");
}, error:function(){
alert("出错啦!");
}
});
@H_
301_0@在上面的
代码中,$.ajax()接受一个对象参数,这个对象包含两个
方法:success
方法指定操作成功后的回调
函数,error
方法指定操作失败后的回调
函数。
@H_
301_0@$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery,返回的是XHR对象,你没法进行链式操作;如果高于1.5.0版本,返回的是deferred对象,可以进行链式操作。
@H_
301_0@有了deferred对象之后,可以这样写了
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });
@H_
301_0@上面
代码中的done()相当于success
方法,fail()相当于error
方法。采用链式写法以后,
代码的可读性大大提高。
@H_
301_0@
2)指定同一操作的多个回调函数
@H_
301_0@deferred对象的一大好处,就是它允许你自由
添加多个回调
函数。
@H_
301_0@还是以上面的
代码为例,如果ajax操作成功后,除了原来的回调
函数,我还想再运行一个回调
函数,怎么办?
@H_
301_0@很简单,直接把它加在后面就行了。
.done(function(){ alert("哈哈,成功了!");} )
.fail(function(){ alert("出错啦!"); } )
.done(function(){ alert("第二个回调函数!");} );
@H_
301_0@回调
函数可以
添加任意多个,它们按照
添加顺序执行。
@H_
301_0@
3)为多个操作指定回调函数
@H_
301_0@deferred对象的另一大好处,就是它允许你为多个事件指定一个回调
函数,这是传统写法做不到的。
@H_
301_0@请看下面的
代码,它用到了一个新的
方法$.when():
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });
@H_
301_0@这段
代码的意思是,先执行两个操作$.ajax("test1.html")和$.ajax("test2.html"),如果都成功了,就运行done()指定的回调
函数;如果有一个失败或都失败了,就执行fail()指定的回调
函数。
@H_
301_0@
4)普通操作的回调函数接口(上)
@H_
301_0@deferred对象的最大优点,就是它把这一套回调
函数接口,从ajax操作扩展到了所有操作。也就是说,任何一个操作----不管是ajax操作还是本地操作,也不管是异步操作还是同步操作----都可以使用deferred对象的各种
方法,指定回调
函数。
@H_
301_0@我们来看一个具体的例子。假定有一个很耗时的操作wait:
var tasks = function(){
alert("执行完毕!");
};
setTimeout(tasks,5000);
};
@H_
301_0@我们为它指定回调
函数,应该怎么做呢?
@H_
301_0@很自然的,你会想到,可以使用$.when():
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });
@H_
301_0@但是,这样写的话,done()
方法会立即执行,起不到回调
函数的作用。原因在于$.when()的参数只能是deferred对象,所以必须对wait()进行改写:
var wait = function(dtd){
var tasks = function(){
alert("执行完毕!");
dtd.resolve(); // 改变deferred对象的执行状态
};
setTimeout(tasks,5000);
return dtd;
};
@H_
301_0@现在,wait()
函数返回的是deferred对象,这就可以
加上链式操作了。
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });
@H_
301_0@wait()
函数运行完,就会
自动运行done()
方法指定的回调
函数。
@H_
301_0@
5)deferred.resolve()方法和deferred.reject()方法
@H_
301_0@jQuery规定,deferred对象有三种执行状态----未完成,已完成和已失败。如果执行状态是"已完成"(resolved),deferred对象立刻
调用done()
方法指定的回调
函数;如果执行状态是"已失败",
调用fail()
方法指定的回调
函数;如果执行状态是"未完成",则继
@H_
301_0@续等待,或者
调用progress()
方法指定的回调
函数(jQuery1.7版本
添加)。
@H_
301_0@前面部分的ajax操作时,deferred对象会根据返回结果,
自动改变自身的执行状态;但是,在wait()
函数中,这个执行状态必须由程序员手动指定。dtd.resolve()的意思是,将dtd对象的执行状态从"未完成"改为"已完成",从而触发done()
方法。
@H_
301_0@类似的,还存在一个deferred.reject()
方法,作用是将dtd对象的执行状态从"未完成"改为"已失败",从而触发fail()
方法。
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("出错啦!"); });
@H_
301_0@
6)deferred.promise()方法
@H_
301_0@上面这种写法,还是有问题。那就是dtd是一个全局对象,所以它的执行状态可以从外部改变。
@H_
301_0@请看下面的
代码:
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();
@H_
301_0@我在
代码的尾部加了一行dtd.resolve(),这就改变了dtd对象的执行状态,因此导致done()
方法立刻执行,跳出"哈哈,成功了!"的
提示框,等5秒之后再跳出"执行完毕!"的
提示框。
@H_
301_0@为了避免这种情况,jQuery提供了deferred.promise()
方法。它的作用是,在原来的deferred对象上返回另一个deferred对象,后者只开放与改变执行状态无关的
方法(比如done()
方法和fail()
方法),
屏蔽与改变执行状态有关的
方法(比如resolve()
方法和
@H_
301_0@reject()
方法),从而使得执行状态不能被改变。
@H_
301_0@请看下面的
代码:
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(); // 此时,这个语句是无效的
@H_
301_0@在上面的这段
代码中,wait()
函数返回的是promise对象。然后,我们把回调
函数绑定在这个对象上面,而不是原来的deferred对象上面。这样的好处是,无法改变这个对象的执行状态,要想改变执行状态,只能操作原来的deferred对象。
@H_
301_0@不过,更好的写法是将dtd对象变成wait()
函数的内部对象。
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("出错啦!"); });
@H_
301_0@
7)普通操作的回调函数接口(中)
@H_
301_0@另一种防止执行状态被外部改变的
方法,是使用deferred对象的建构
函数$.Deferred()。
@H_
301_0@这时,wait
函数还是保持不变,我们直接把它传入$.Deferred():
@H_
301_0@jQuery规定,$.Deferred()可以接受一个
函数名(注意,是
函数名)作为参数,$.Deferred()所
生成的deferred对象将作为这个
函数的默认参数。
@H_
301_0@
8)普通操作的回调函数接口(下)
@H_
301_0@除了上面两种
方法以外,我们还可以直接在wait对象上部署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);
@H_
301_0@这里的关键是dtd.promise(wait)这一行,它的作用就是在wait对象上部署Deferred接口。正是因为有了这一行,后面才能直接在wait上面
调用done()和fail()。
@H_
301_0@
2 extend方法
@H_
301_0@
JQuery的extend扩展方法:
@H_301_0@Jquery的扩展方法extend是我们在写插件的过程中常用的方法,该方法有一些重载原型,在此,我们一起去了解了解。
@H_301_0@1)Jquery的扩展方法原型是:
@H_301_0@extend(dest,src1,src2,src3...);
@H_301_0@它的含义是将src1,src3...合并到dest中,返回值为合并后的dest,由此可以看出该方法合并后,是修改了dest的结构的。如果想要得到合并的结果却又不想修改dest的结构,可以如下使用:
@H_301_0@var newSrc=$.extend({},src3...)//也就是将"{}"作为dest参数。
@H_301_0@这样就可以将src1,src3...进行合并,然后将合并结果返回给newSrc了。如下例:
@H_301_0@var result=$.extend({},{name:"Tom",age:21},{name:"Jerry",sex:"Boy"})
@H_301_0@那么合并后的结果
@H_301_0@result={name:"Jerry",age:21,sex:"Boy"}
@H_301_0@也就是说后面的参数如果和前面的参数存在相同的名称,那么后面的会覆盖前面的参数值。
@H_301_0@2)省略dest参数
@H_301_0@上述的extend方法原型中的dest参数是可以省略的,如果省略了,则该方法就只能有一个src参数,而且是将该src合并到调用extend方法的对象中去,如:
@H_301_0@$.extend(src)
@H_301_0@该方法就是将src合并到jquery的全局对象中去,如:
@H_301_0@就是将hello方法合并到jquery的全局对象中。
@H_301_0@$.fn.extend(src)
@H_301_0@该方法将src合并到jquery的实例对象中去,如:
@H_301_0@就是将hello方法合并到jquery的实例对象中。
@H_301_0@下面例举几个常用的扩展实例:
@H_301_0@$.extend({net:{}});
@H_301_0@这是在jquery全局对象中扩展一个net命名空间。
@H_301_0@这是将hello方法扩展到之前扩展的Jquery的net命名空间中去。
@H_301_0@3)Jquery的extend方法还有一个重载原型:
@H_301_0@extend(boolean,dest,src3...)
@H_301_0@第一个参数boolean代表是否进行深度拷贝,其余参数和前面介绍的一致,什么叫深层拷贝,我们看一个例子:
@H_301_0@我们可以看出src1中嵌套子对象location:{city:"Boston"},src2中也嵌套子对象location:{state:"MA"},第一个深度拷贝参数为true,那么合并后的结果就是:
@H_301_0@也就是说它会将src中的嵌套子对象也进行合并,而如果第一个参数boolean为false,我们看看合并的结果是什么,如下:
@H_301_0@那么合并后的结果就是:
@H_301_0@result={name:"John",location:{state:"MA",county:"China"}}
@H_301_0@以上是网上看到的两篇分别对jQuery中的deferred对象和extend方法的介绍,感觉比较详细而且容易理解,所以把它们整理到一起与大家分享!
@H_301_0@以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持编程之家!