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的滚动新闻列表
Jun 19 Javascript
Prototype源码浅析 String部分(一)之有关indexOf优化
Jan 15 Javascript
Javascript基础教程之for循环
Jan 18 Javascript
Jquery Easyui进度条组件Progress使用详解(8)
Mar 26 Javascript
Angular网络请求的封装方法
May 22 Javascript
jQuery实现的简单对话框拖动功能示例
Jun 05 jQuery
解决vue select当前value没有更新到vue对象属性的问题
Aug 30 Javascript
从源码里了解vue中的nextTick的使用
Nov 22 Javascript
深入学习JavaScript中的bom
May 27 Javascript
微信小程序实现语音识别转文字功能及遇到的坑
Aug 02 Javascript
微信小程序封装分享与分销功能过程解析
Aug 13 Javascript
Vue使用CDN引用项目组件,减少项目体积的步骤
Oct 30 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默认设置中的Notice警告的方法
2016/05/20 PHP
PHP微信开发之查询城市天气
2016/06/23 PHP
PHP+Mysql无刷新问答评论系统(源码)
2016/12/20 PHP
laravel-admin 实现给grid的列添加行数序号的方法
2019/10/08 PHP
扩展String功能方法
2006/09/22 Javascript
JavaScript 字符串连接性能优化
2008/12/20 Javascript
javascript中使用正则计算中文长度的例子
2014/04/29 Javascript
JavaScript错误处理
2015/02/03 Javascript
jquery插件bxslider用法实例分析
2015/04/16 Javascript
javascript实现tab切换的两个实例
2015/11/05 Javascript
node.js从数据库获取数据
2016/05/08 Javascript
AngularJS控制器之间的通信方式详解
2016/11/03 Javascript
vuex操作state对象的实例代码
2018/04/25 Javascript
一个简单的node.js界面实现方法
2018/06/01 Javascript
微信小程序methods中定义的方法互相调用的实例代码
2018/08/07 Javascript
如何在JavaScript中优雅的提取循环内数据详解
2019/03/04 Javascript
在layui tab控件中载入外部html页面的方法
2019/09/04 Javascript
vue中使用element ui的弹窗与echarts之间的问题详解
2019/10/25 Javascript
通过实例解析chrome如何在mac环境中安装vue-devtools插件
2020/07/10 Javascript
[07:08]2014DOTA2西雅图国际邀请赛 小组赛7月11日TOPPLAY
2014/07/11 DOTA
编写Python的web框架中的Model的教程
2015/04/29 Python
Python 使用PIL numpy 实现拼接图片的示例
2018/05/08 Python
vscode调试django项目的方法
2020/08/06 Python
css3实现元素环绕中心点布局的方法示例
2019/01/15 HTML / CSS
最热门的自我评价
2013/12/30 职场文书
两年的个人工作自我评价
2014/01/10 职场文书
业务员的岗位职责
2014/03/15 职场文书
给校长的建议书400字
2014/05/15 职场文书
感恩教师节演讲稿
2014/09/03 职场文书
2014年群众路线教育实践活动整改措施
2014/09/24 职场文书
党员批评与自我批评
2014/10/15 职场文书
泰坦尼克号观后感
2015/06/04 职场文书
2015少先队大队辅导员工作总结
2015/07/24 职场文书
分析Netty直接内存原理及应用
2021/06/14 Java/Android
PYTHON使用Matplotlib去实现各种条形图的绘制
2022/03/22 Python
利用Redis实现点赞功能的示例代码
2022/06/28 Redis