jquery延迟对象解析


Posted in Javascript onOctober 26, 2016

技术一般水平有限,有什么错的地方,望大家指正。

ES6已经实现了延迟对象Promise,但是今天主角是JQ里面的延迟对象,套路其实都是差不多的。下面先看一个比较牵强的例子:

<button id="add">add</button><button id="remove">remove</button>
<div id="content"></div>
$(function(){
  var dfd = new $.Deferred();
  var add = $("#add");
  var remove = $("#remove");
  var content = $("#content");
  add.click(function(){
    var span = $("<span>我是点击按钮创建的元素</span>");
    $("span").length==0&&$("body").append(span);
    dfd.resolve();
  })
  remove.click(function(){
    var span = $("span");
    span&&span.remove();
  })
  dfd.done(function(){
    $("span").css("color","red");
  })
})

现在先聚焦功能,我们点击add按钮可以看到span元素添加并且颜色变红。然后在看我们代码中的的异类的东西,开始的var dfd = new $.Deferred();以及add事件函数中的dfd.resolve();还有就是最后面的dfd.done(function(){$("span").css("color","red");})。

$.Deferred()就是我们今天介绍的重点---JQ中的延迟对象,所谓延迟就是在以后的某段事件可以运行。我们看上面的代码的一个处理流程,在上面的代码中我们调用新建的延迟对象的dfd.done()方法的参数位置传递了一个匿名函数表达式,在点击事件的处理函数执行时调用dfd.resolve(),之后我们写在dfd.done()里面的匿名函数就执行了,在这个过程中我们可以看做,dfd把done里面的函数放在resolve的位置了。dfd就是延迟对象,很明显它可以改变函数的执行顺序。

在看上面的这段代码你仔细一想就会发现有个毛用啊,我们把改变颜色的代码放在一个函数里面,点击的时候调用这个函数不就好了,写这么麻烦有个鸟用。其实延迟对象最多的是应用在AJAX中。上面的代码我们点击add之后我们在点击remove然后在点击add这时候发现这次的字没有变成红色,这是因为延迟对象的状态变化之后就失效了,说白了就是一次性的。

延迟对象使用

JQ为我们实现了延迟对象的功能,我们一般称为Deferred或者Promise,基本上是一个东西,确切的说Promise是从Deferred中派生的一个子类。

我们在使用的时候首先就是创建一个延迟对象:var dfd = new $.Deferred()。

延迟对象dfd有三种状态分别为pending,resolved,rejected,我们可以通过对dfd对象使用state方法来查看此时的状态:dfd.state()。

dfd在创建出来之后他的状态为pending,调用resolve方法之后:dfd.resolve()它的状态就会变为resolved然后会执行dfd.done()里面的函数,dfd调用reject方法之后:dfd.reject()它的状体就会变为rejected然后会执行dfd.fail()里面的方法,并且dfd对象在从pending变为resolved或者rejected之后就不会再发生任何变化,这也就是我们上面的代码为什么只能在第一次点击之后的文字是红的的原因。

jquery延迟对象解析

我们在来看一看开始的代码,我们的dfd.done()中定义了字体变红的函数,在点击函数执行后dfd调用resolve,之后dfd的状态从pending变为resolved会执行done里面的方法继而颜色变红。

dfd.resolve()和dfd.done()之间是可以进行参数传递的,现在我们对开始的代码做一些修改:

//done里面的修改如下
dfd.done(function(color){$("span").css("color",color)})
//点击事件的处理函数修改如下
dfd.resolve("green");

我们在点击之后字体颜色变为绿色了。

另外dfd还有另外一个函数always:dfd.always(),dfd的状态从pending变为哪个状态always里面的函数都会执行。

dfd的每一个方法都会返回一个延迟对象,所以done,fail,always都是可以有多个的,可以直接写成链式调用:

dfd.done(function(){}).done(function(){}).fail(function(){});

 

dfd的无论哪个API都可以写多个,这时候我们就可能会考虑它的执行顺序能不能保证。这点我们完全可以放心,dfd的函数执行的顺序是完全没有问题的按照我们书写的顺序执行,看下面的代码:

dfd.done(function(){
  var span = $("<span>我是点击按钮创建的元素</span>");
  $("span").length==0&&$("body").append(span);
})
.done(function(color){
  $("span").css("color",color)});
})

 

第一个函数添加元素,第二个函数改变添加元素的颜色。

无论什么时候dfd三个API里面的函数都会在dfd的状态从pending变化之后才能执行,在异步的情况下如此,在同步的情况下也是。更确切的说dfd在调用dfd.resolve()之后已经执行过的done的里面的函数会立即执行,对于dfd.resolve()后面的done来说当程序走到它那时才会执行:

var dfd = new $.Deferred();
dfd.done(function(){console.log(1)});
dfd.done(function(){console.log(2)});
console.log("resolve before");
dfd.resolve();
console.log("resolve after");
dfd.done(function(){console.log(3)});
//resolve before,1,2,resolve after,3

延迟对象示例

最开始我们使用JQ的AJAX的时候我们通常的写法是:

$.ajax({
 url:"x/y",
 type:"post",
 data:"{...}",
 contentType:"application/json; charset=utf-8",
 success:function(){},
 error:function(){}
})

在1.5(好像是这个版本~)之后AJAX会返回一个Promise对象,继而我们可以写成下面这种:

$.ajax({
 url:"x/y",
 type:"post",
 data:"{...}",
 contentType:"application/json; charset=utf-8",
}).done(function(){})
.fail(function(){})

看起来更骚气了一点,而且这我们还可以在加多个.done(function(){}),每个done处理不同的事情这样看起来比较清晰。

已经知道延迟对象可以改变代码的执行顺序,假如我们又下面的代码:

$.ajax({
 url:"取数据",
 type:"post",
 contentType:"xxx"
}).done(function(data){
  $.ajax({
    url:"利用data取数据",
    data:data,
    type:"post",
    contentType:"xxxx"
  }).done(function(data){
    use data to _do sth...
  })
})

我们会发现嵌套的有点多了,我们就可以利用延迟对象让他看起来更加好看一点:

var dfd = new $.Deferred();
$.ajax({
 url:"取数据",
 type:"post",
 contentType:"xxx"
}).done(function(data){
  dfd.resolve(data);
})
dfd.done(function(data){
  $.ajax({
    url:"利用data取数据",
    data:data,
    type:"post",
    contentType:"xxxx"
  }).done(function(data){
    use data to _do sth...
  })
})

没有延迟对象我们一样能完成需要的功能,此时我们就需要一层一层嵌套我们处理过程了,而有了延迟对象我们就可以避免这种事了,他可以轻松控制代码的执行顺序,让代码看起来更请清晰。你可能会说我封装函数在合适的地方调不就行了,如果自己看自己写的代码没问题,但是换一个人他的滚动条可能就一直上上下下了。

延迟对象的里一个作用就是可以合并AJAX的调用,比如一个接口取数据A另一个接口取数据B,AB都取到之后我们在利用这些数据做一些喜欢做的事,我们就可以利用延迟对象轻松实现。此时我们就可以利用JQ的$.when()来实现。$.when()就跟他的名字一样-当什么的时候-,他的参数可以是Promise对象,也可以是字符串(很少遇到不在介绍),他的返回结果也是一个Promise对象,下面看一个小例子: 

var allData = {};
  var dataA = $.ajax({
    url:"获取A的URL",
    type:"post",
  }).done(function(data){
    allData.a = data;
  });
  var dataB = $.ajax({
    url:"获取B的URL",
    type:"post",
  }).done(function(data){
    allData.b = data;
  });
  $.when(dataA,dataB).done(function(){
    use allData to _do sth...
  });

allData是保存所有数据的一个集合,dataA是第一个AJAX返回的Promise对象,dataB是第二个。$.when()的done方法执行的唯一条件就是dataA和dataB都执行成功。

补充:dfd还有一对组合就是notify+progress当dfd对象的状态处于pending时可以调用dfd.nothfy(),调用之后dfd.progress()里面的函数会执行,只要dfd处于pending状态dfd.notify()就可以一直调用,同样也可以传递参数。

Javascript 相关文章推荐
js调试工具 Javascript Debug Toolkit 2.0.0版本发布
Dec 02 Javascript
Jquery 扩展方法
May 06 Javascript
document.documentElement的一些使用技巧
Apr 18 Javascript
javascript:FF/Chrome与IE动态加载元素的区别说明
Jan 26 Javascript
jQuery基于扩展实现的倒计时效果
May 14 Javascript
Node.js中npm常用命令大全
Jun 09 Javascript
Javascript中字符串和数字的操作方法整理
Jan 22 Javascript
js 动态生成html 触发事件传参字符转义的实例
Feb 14 Javascript
在ABP框架中使用BootstrapTable组件的方法
Jul 31 Javascript
JS简单获取并修改input文本框内容的方法示例
Apr 08 Javascript
在Vue methods中调用filters里的过滤器实例
Aug 30 Javascript
微信小程序 简易计算器实现代码实例
Sep 02 Javascript
关于Jquery中的bind(),on()绑定事件方式总结
Oct 26 #Javascript
JavaScript实现的微信二维码图片生成器的示例
Oct 26 #Javascript
关于JavaScript中事件绑定的方法总结
Oct 26 #Javascript
WEB 前端开发中防治重复提交的实现方法
Oct 26 #Javascript
jquery+css3问卷答题卡翻页动画效果示例
Oct 26 #Javascript
简单的js计算器实现
Oct 26 #Javascript
利用python分析access日志的方法
Oct 26 #Javascript
You might like
一篇入门的php Class 文章
2007/04/04 PHP
PHP5中使用DOM控制XML实现代码
2010/05/07 PHP
php常用文件操作函数汇总
2014/11/22 PHP
[原创]php正则删除html代码中class样式属性的方法
2017/05/24 PHP
php识别翻转iphone拍摄的颠倒图片
2018/05/17 PHP
PHP PDOStatement::columnCount讲解
2019/01/30 PHP
thinkphp5 + ajax 使用formdata提交数据(包括文件上传) 后台返回json完整实例
2020/03/02 PHP
JS在TextArea光标位置插入文字并实现移动光标到文字末尾
2013/06/21 Javascript
jquery实现页面百叶窗走马灯式翻滚显示效果的方法
2015/03/12 Javascript
学习Bootstrap组件之下拉菜单
2015/07/28 Javascript
详解AngularJS中$http缓存以及处理多个$http请求的方法
2016/02/06 Javascript
JS数组操作(数组增加、删除、翻转、转字符串、取索引、截取(切片)slice、剪接splice、数组合并)
2016/05/20 Javascript
一个简单不报错的summernote 图片上传案例
2016/07/11 Javascript
一个非常好用的文字滚动的案例,鼠标悬浮可暂停[两种方案任选]
2016/12/01 Javascript
BootStrap table实现表格行拖拽效果
2018/12/01 Javascript
[03:11]完美世界DOTA2联赛PWL DAY8集锦
2020/11/09 DOTA
仅用50行代码实现一个Python编写的计算器的教程
2015/04/17 Python
Python中使用urllib2模块编写爬虫的简单上手示例
2016/01/20 Python
python使用Turtle库绘制动态钟表
2018/11/19 Python
利用python实现冒泡排序算法实例代码
2019/12/01 Python
利用Vscode进行Python开发环境配置的步骤
2020/06/22 Python
pycharm2020.1.2永久破解激活教程,实测有效
2020/10/29 Python
亚马逊墨西哥站:Amazon.com.mx
2018/08/26 全球购物
美国最大的电子宠物训练产品制造商:PetSafe
2018/10/12 全球购物
在职研究生自我鉴定
2013/10/16 职场文书
自我鉴定注意事项
2014/01/19 职场文书
追悼会子女答谢词
2014/01/28 职场文书
青年文明号服务承诺
2014/03/31 职场文书
团结演讲稿范文
2014/05/23 职场文书
安全生产目标管理责任书
2014/07/25 职场文书
计划生育诚信协议书
2014/11/02 职场文书
技术支持岗位职责
2015/02/13 职场文书
2015年妇委会工作总结
2015/05/22 职场文书
男方家长婚礼答谢词
2015/09/29 职场文书
golang中的并发和并行
2021/05/08 Golang
Centos系统通过Docker安装并搭建MongoDB数据库
2022/04/12 MongoDB