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 相关文章推荐
jQuery 类twitter的文本字数限制带提示效果插件
Apr 16 Javascript
js DOM的学习笔记
Dec 22 Javascript
Ajax局部更新导致JS事件重复触发问题的解决方法
Oct 14 Javascript
jQuery实现Div拖动+键盘控制综合效果的方法
Mar 10 Javascript
js实现input密码框提示信息的方法(附html5实现方法)
Jan 14 Javascript
jQuery获取table行数并输出单元格内容的实现方法
Jun 30 Javascript
javascript中获取class的简单实现
Jul 12 Javascript
探究JavaScript中的五种事件处理程序方式
Dec 07 Javascript
vuejs 单文件组件.vue 文件的使用
Jul 28 Javascript
解决Vue使用mint-ui loadmore实现上拉加载与下拉刷新出现一个页面使用多个上拉加载后冲突问题
Nov 07 Javascript
Vue 按照创建时间和当前时间显示操作(刚刚,几小时前,几天前)
Sep 10 Javascript
手把手教你如何编译打包video.js
Dec 09 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用正则表达式匹配中文实例详解
2013/11/06 PHP
php实现插入排序
2015/03/29 PHP
PHP检测用户语言的方法
2015/06/15 PHP
php语言中使用json的技巧及json的实现代码详解
2015/10/27 PHP
PHP实现图的邻接矩阵表示及几种简单遍历算法分析
2017/11/24 PHP
Laravel统一错误处理为JSON的方法介绍
2020/10/18 PHP
一个基于jquery的图片切换效果
2010/07/06 Javascript
js 获取计算后的样式写法及注意事项
2013/02/25 Javascript
javascript静态页面传值的三种方法分享
2013/11/12 Javascript
ExtJS4中的requires使用方法示例介绍
2013/12/03 Javascript
jquery的trigger和triggerHandler的区别示例介绍
2014/04/20 Javascript
js创建对象的方式总结
2015/01/10 Javascript
JavaScript判断数组重复内容的两种方法(推荐)
2016/06/06 Javascript
AngularJS equal比较对象实例详解
2016/09/14 Javascript
EasyUI 结合JS导出Excel文件的实现方法
2016/11/10 Javascript
微信小程序 支付功能开发错误总结
2017/02/21 Javascript
vue基础之事件v-onclick=&quot;函数&quot;用法示例
2019/03/11 Javascript
微信小程序云开发 搭建一个管理小程序
2019/05/17 Javascript
详解element-ui表格中勾选checkbox,高亮当前行
2019/09/02 Javascript
JavaScript ES6 Class类实现原理详解
2020/05/08 Javascript
TypeScript 引用资源文件后提示找不到的异常处理技巧
2020/07/15 Javascript
Python写的贪吃蛇游戏例子
2014/06/16 Python
python时间日期函数与利用pandas进行时间序列处理详解
2018/03/13 Python
Django 大文件下载实现过程解析
2019/08/01 Python
详解python中index()、find()方法
2019/08/29 Python
Burberry英国官网:英国标志性奢侈品牌
2017/03/29 全球购物
澳洲的服装老品牌:SABA
2018/02/06 全球购物
JustFab加拿大:女鞋、靴子、手袋和服装在线
2018/05/18 全球购物
《荷花》教学反思
2014/04/16 职场文书
贫困证明模板(3篇)
2014/09/16 职场文书
大学生就业推荐表自我评价
2015/03/02 职场文书
2015年为民办实事工作总结
2015/05/26 职场文书
主婚人致辞精选
2015/07/28 职场文书
Html分层的box-shadow效果的示例代码
2021/03/30 HTML / CSS
Mysql分析设计表主键为何不用uuid
2022/03/31 MySQL
python神经网络学习 使用Keras进行简单分类
2022/05/04 Python