之前的时候,碰到过几次同事问我,说js的同步怎么处理,就是我想先执行这段代码(耗时相对较长的一行,多数是异步的一些api调用),执行完了之后我再执行下边这句,每次我都很无奈的说不晓得,如果是ajax的话我知道async可以搞定,当然这并没有什么卵用。近段时间在做一个自动化测试的项目,前后端分离的。旁边的同事要做前端websql的增删改查,一直在说jquery的deferred如何如何,我也不懂,就感觉听上去高大上的一个东西,内心忐忑之余就找两篇文章读了一下,然后就有了此文。

------------------------------------------------------------------------------------------------------------------------------------------------------------

  js如何执行的问题:js不是严格一行一行的执行的,它是一段一段的进行解析,这个解析过程主要是对声明的提前,剩余的基本上还是按照先后顺序执行的。js是单线程的,正常情况下的确是先执行上一行然后下一行的,那很多异步的api是怎么实现的呢,执行队列。关于这里可以参考这篇文章:http://www.cnblogs.com/3body/p/5691744.html,关于同步的问题怎么实现呢,依然不好搞,但可以通过回调函数让它看起来是同步的。 

在回调函数方面,jquery的功能比较弱,为了改变这一点,jquery团队设计了deferred对象。简单来说,deferred对象就是jquery的回调函数解决方案。在英语中,defer的意思是“延迟”,所以deferred对象的含义就是延迟到未来某个时间点再来执行。Deferred对象是jquery从1.5.0开始引入的,它彻底改变了如何在jquery中使用ajax。为了实现它,jquery的全部ajax代码都被改写了。
jquery1.5之前的版本,ajax返回的是XHR(xmlHttpRequest)对象,可以从jquery的api中看到:

从1.5开始,返回的还是xhr对象,但是这个对象实现了deferred的接口方法,所以可以当成deferred使用,也因此,jquery的ajax可以有了deferred版本的写法:
原来我们的ajax写法: 

$.ajax({
url: "test.html",
success: function(){
alert("哈哈,成功了!");
},
error:function(){
alert("出错啦!");
}
});

  如果是1.5之后的jquery,可以这么写:

$.ajax("test.html")
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });

 deferred对象究竟长啥样子,我们可以看图:

 

  这里边有几个常用方法,resolve()表示将deferred的状态置为已解决也就是成功,reject()表示把状态置为失败,done()是执行成功的回调函数,fail是失败的回调函数,always()是无论如何都会执行的函数,类似于try...catch的finally,progress()是状态变为开始执行的回调函数,state()可以获取deferred对象的状态。
  如何使用这个deferred对象呢?

  1、其实前面的代码中已经使用了,$.ajax(url).done(function(){}).fail(function(){})这行代码中,$.ajax()返回了一个deferred对象,然后我们链式的调用,使用了这个对象的done跟fail方法来设定了两个回调函数;
  2、如果我要判断多个方法执行完成后再调用某个函数,怎么做呢?
   这里要用到$.when()

$.when($.ajax("test1.html"), $.ajax("test2.html"))
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出错啦!"); });

  3、如果我不是ajax呢,自己手写的函数怎么做呢,让函数返回一个deferred对象即可:

function a(){
var d1 = $.Deferred();
d1.resolve("aa","bb",{"myaa":"xxxx"});
return d1;
} function b(){
var d2 = $.Deferred();
d2.reject();
return d2;
} $.when(a(),b())
.done(function(a,b,c){debugger;alert("success"+a);})
.fail(function(){alert("error");})

  顺便我们可以看到,deferred对象可以传参!只是要注意的是resolve方法里边的参数不管有几个,最后会以一个数组的形式传给回调函数,回调函数只有一个接收参数。上述代码只要a(),b()一个rejected则fail,将b修改为resolved,则执行结果如下:

  

  可以看到只有a有值,其它两个参数都在回调函数第一个参数的两个数组元素中。

  这里有个要注意的地方,就是$.when()只接收deferred对象,如果你传给when的不是deferred对象,会发现函数会马上执行的,起不到回调的作用;
  我们很容易发现一个问题,deferred对象的状态是可以手动代码修改的,因为resolve()就可以置为成功,reject()就可以置为失败,在复杂代码环境下这个太危险了。因此有了promise对象。
  我本地用的jquery-1.11.3,看上面deferred的结构图可以看到有个方法叫promise(),这个就是返回一个pormise对象。这个pormise对象跟deferred是非常类似的,差别就是promise对象去掉了reject()跟resolve()方法,也就是不对外提供修改状态的方法,免得多方调用引起混乱。其实jquery返回的就是个promise对象,我们想改状态是改不了的。看一下ajax返回对象跟pormise的结构图:

  

          图:ajax  XHR

  

          图:promise

  我们可以很清晰的看到这两个promise比deferred少了resolve,resolveWith,reject,rejectWith等这些改变对象状态的方法。promise不希望我们能手动更改promise对象的状态。因为:假设场景中,我们返回promise对象给它人使用,这个对象被a跟b两个方法引用了,a方法改变了promise的状态,那么这会对b方法造成影响,这是很不安全的。

  那么,deferred跟promise就是为了帮助我们实现同步编程的吗?
  你可以这么认为,其实我们需要的只是一个回调而已。准确的说,deferred仅仅是一种回调方案而已,它可以使我们方便的书写异步代码,也可以使得我们的代码看上去更加优雅。

  比如,一段动画的代码:

$('.animateEle').animate({
opacity:'.5'
}, 4000,function(){
$('.animateEle2').animate({
width:'100px'
},2000,function(){
// 这样太伤了
$('.animateEle3').animate({
height:'0'
},2000);
});
});

  我们可以这么写:

var animate1 = function() {
return $('.animateEle1').animate({opacity:'.5'},4000).promise();
};
var animate2 = function() {
return $('.animateEle2').animate({width:'100px'},2000).promise();
};
var animate3 = function(){
return $('.animateEle3').animate({height:'0'},2000).promise();
}; $.when(animate1()).then(animate2).then(animate3);

  后一种明显比第一种看起来要思路清晰,它避免了代码的嵌套,看起来也更舒服一些。

  

------------------------------------------------------------------------------------------------------------------------------------------------------------

  额,就这些了,看了个大概,不知有没有错误的地方,,,请指出改正。

Deferred跟promise跟js同步问题记录的更多相关文章

  1. 使用 jQuery Deferred 和 Promise 创建响应式应用程序

    这篇文章,我们一起探索一下 JavaScript 中的 Deferred 和 Promise 的概念,它们是 JavaScript 工具包(如Dojo和MochiKit)中非常重要的一个功能,最近也首 ...

  2. js同步、异步、回调的执行顺序以及闭包的理解

    首先,记住同步第一.异步第二.回调最末的口诀 公式表达:同步=>异步=>回调 看一道经典的面试题: for (var i = 0; i < 5; i++) { setTimeout( ...

  3. 2017、2018面试分享(js面试题记录)记得点赞分享哦;让更多的人看到~~

    2017面试分享(js面试题记录) 1. 最简单的一道题 '11' * 2 'a8' * 3 var a = 2, b = 3; var c = a+++b; // c = 5 2. 一道this的问 ...

  4. js 实现键盘记录 兼容FireFox和IE

    这两天突然想弄弄js的键盘记录,所以就小研究了一下. 主要分四个部分 第一部分:浏览器的按键事件 第二部分:兼容浏览器 第三部分:代码实现和优化 第四部分:总结 第一部分:浏览器的按键事件 用js实现 ...

  5. js实用方法记录-js动态加载css、js脚本文件

    js实用方法记录-动态加载css/js 附送一个加载iframe,h5打开app代码 1. 动态加载js文件到head标签并执行回调 方法调用:dynamicLoadJs('http://www.yi ...

  6. js实用方法记录-简单cookie操作

    js实用方法记录-简单cookie操作 设置cookie:setCookie(名称,值,保存时间,保存域); 获取cookie:setCookie(名称); 移除cookie:setCookie(名称 ...

  7. js实用方法记录-指不定哪天就会用到的js方法

    js实用方法记录-指不定哪天就会用到的js方法 常用或者不常用都有 判断是否在微信浏览器中 测试代码:isWeiXin()==false /** * 是否在微信中 */ function isWeix ...

  8. js同步-异步-回调

    出处:https://blog.csdn.net/u010297791/article/details/71158212(1)上面主要讲了同步和回调执行顺序的问题,接着我就举一个包含同步.异步.回调的 ...

  9. js小功能记录

    个人日常中遇到的js小功能记录,方便查看. /** * 判断是否包含字符串某字符串 * @param {[type]} str [被检测的字符串] * @param {[type]} substr [ ...

随机推荐

  1. SPOJ - BALNUM Balanced Numbers(数位dp+三进制状压)

    Balanced Numbers Balanced numbers have been used by mathematicians for centuries. A positive integer ...

  2. ElementUI的表单和vee-validate结合使用时发生冲突的解决

    在Vue项目中使用ElementUI表单时,同时又引入了vee-validate进行使用的时候,在浏览器上会出现这样的报错: [Vue warn]: The computed property &qu ...

  3. 关注java技术相关公众号

    1.江南一点雨 关注公众号,回复 Java ,获取 Java干货! 个人博客:http://www.javaboy.org/ 2. 芋道源码 github地址:https://github.com/Y ...

  4. SQL/T-SQL实例参考-1

    CASE ,D.[Score] B_Score ,'Distince'= CASE WHEN C.Score > D.Score THEN C.[Score] - D.[Score] WHEN ...

  5. day06.2-软链接与硬链接

    1. 建立软链接:ln   -s   源文件   链接文件 特点:a). 相当于Windons系统中的快捷方式:        b). 删除链接文件不影响源文件内容,而删除源文件后链接文件随即失效: ...

  6. webpack4 入门(二)

    一.管理输出 1.多入口配置 entry: { index1: './src/index.js', index2: './src/index2.js' }, output: { filename: ' ...

  7. Bridge Across Islands POJ - 3608 旋转卡壳求凸包最近距离

    \(\color{#0066ff}{题目描述}\) 几千年前,有一个小王国位于太平洋的中部.王国的领土由两个分离的岛屿组成.由于洋流的冲击,两个岛屿的形状都变成了凸多边形.王国的国王想建立一座桥来连接 ...

  8. kuangbin专题七 HDU1166 敌兵布阵 (线段树或树状数组)

    C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于 ...

  9. 洛谷P3507 [POI2010]GRA-The Minima Game

    题目描述 Alice and Bob learned the minima game, which they like very much, recently. The rules of the ga ...

  10. Qt 学习之路 2(11):布局管理器

    Home / Qt 学习之路 2 / Qt 学习之路 2(11):布局管理器 Qt 学习之路 2(11):布局管理器  豆子  2012年9月4日  Qt 学习之路 2  70条评论 所谓 GUI 界 ...