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 相关文章推荐
JavaScript中判断对象类型的几种方法总结
Nov 11 Javascript
JS简单的图片放大缩小的两种方法
Nov 11 Javascript
原始XMLHttpRequest方法详情回顾
Nov 28 Javascript
js实现每日自动换一张图片的方法
May 04 Javascript
JavaScript中toString()方法的使用详解
Jun 05 Javascript
Bootstrap导航条鼠标悬停下拉菜单
Jan 04 Javascript
react.js 翻页插件实例代码
Jan 19 Javascript
vue2.0父子组件及非父子组件之间的通信方法
Jan 21 Javascript
Node.js使用gm拼装sprite图片
Jul 04 Javascript
Node.js中环境变量process.env的一些事详解
Oct 26 Javascript
解决在vue项目中,发版之后,背景图片报错,路径不对的问题
Mar 06 Javascript
深入理解JS异步编程-Promise
Jun 03 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框架Phpbean说明
2008/01/10 PHP
php 进度条实现代码
2009/03/10 PHP
PHP 长文章分页函数 带使用方法,不会分割段落,翻页在底部
2009/10/22 PHP
Notice: Undefined index: page in E:\PHP\test.php on line 14
2010/11/02 PHP
求PHP数组最大值,最小值的代码
2011/10/31 PHP
PHP单例模式详细介绍
2015/07/01 PHP
PHP使用PHPExcel删除Excel单元格指定列的方法
2016/07/06 PHP
php微信公众平台示例代码分析(二)
2016/12/06 PHP
解决Laravel blade模板转义html标签的问题
2019/09/03 PHP
js截取固定长度的中英文字符的简单实例
2013/11/22 Javascript
js opener的使用详解
2014/01/11 Javascript
JS实现控制表格只显示行边框或者只显示列边框的方法
2015/03/31 Javascript
js实现a标签超链接提交form表单的方法
2015/06/24 Javascript
jquery地址栏链接与a标签链接匹配之特效代码总结
2015/08/24 Javascript
微信小程序微信支付接入开发实例详解
2017/04/12 Javascript
JS实现图片上传多次上传同一张不生效的处理方法
2018/08/06 Javascript
JavaScript中.min.js和.js文件的区别讲解
2019/02/13 Javascript
微信小程序如何调用json数据接口并解析
2019/06/29 Javascript
手写Vue弹窗Modal的实现代码
2019/09/11 Javascript
微信小程序swiper左右扩展各显示一半代码实例
2019/12/05 Javascript
原生js实现的观察者和订阅者模式简单示例
2020/04/18 Javascript
Javascript实现鼠标移入方向感知
2020/06/24 Javascript
可拖拽组件slider.js使用方法详解
2020/12/04 Javascript
[01:03]悬念揭晓 11月26日DOTA2完美盛典不见不散
2017/11/23 DOTA
Python3 加密(hashlib和hmac)模块的实现
2017/11/23 Python
基于Pandas读取csv文件Error的总结
2018/06/15 Python
Django使用Channels实现WebSocket的方法
2019/07/28 Python
利用python读取YUV文件 转RGB 8bit/10bit通用
2019/12/09 Python
如何实现jdbc性能优化
2012/07/30 面试题
大学毕业生个人自荐信范文
2014/01/08 职场文书
素质拓展感言
2014/01/29 职场文书
2014广电局实施党的群众路线教育实践活动方案思想汇报
2014/09/22 职场文书
党的群众路线教育实践活动个人批评与自我批评
2014/10/16 职场文书
信访稳定工作汇报
2014/10/27 职场文书
毕业生政审意见范文
2015/06/04 职场文书
《曾国藩家书》读后感——读家书,立家风
2019/08/21 职场文书