jq控制两个函数执行的前后顺序——deferred对象

本文介绍了如何利用jQuery的Deferred对象解决异步函数间执行顺序问题,避免回调地狱,同时强调了其在1.5版本后的浏览器兼容性和普通函数操作的优势。通过实例展示了$.when()和dfd对象的使用,以及与Promise对象的区别.
摘要由CSDN通过智能技术生成

开篇先写中心:借助deferred对象,jq可自主控制不同函数之间执行顺序。

问题场景

经历过一些项目后,我们经常会遇到一类问题:有两个函数a和b,我们总是希望a函数运行成功后,再调用b函数,或者b函数中某个参数,需要用到a函数产生的数据,而不得不等待a函数执行结束,归根结底,我们需要的是a函数和b函数甚至c函数有限制好的执行顺序。

  • setTimeout():最初遇到这类问题,我可能会依赖于setTimeout()方法,但是用setTimeout改变函数执行顺序会出现很多问题,首先是时间设定,可能过短,导致顺序错乱,可能过长,导致函数执行时卡顿。其次当同一页面使用setTimeout过多,函数之间可能出现交叉、互相影响的现象,从而出现不可预料的bug。
  • 回调函数:回调函数是使用比较广泛的方式。因为本文的重点不在回调函数,而且这也不是一个友好的实现方式,回调地狱的大名在异步代码中如雷贯耳。不细究概念,从代码来看,可以简单列举两个例子:
    一种是在异步代码的回调中,调用另一个异步。
$.ajax({
……
success:function(result){
	$.ajax({
	……
	success:function(){
	}
	})
}
})

这段代码的意思是当一个ajax请求成功后,再执行另一个ajax请求,目的就是控制两个ajax的运行顺序,如果不在sucess回调中执行另一个ajax请求,两个ajax请求的先后顺序是无法保证的。
另一种是将函数作为参数传递给另一个函数。

function a(){
a的执行代码
}
function b(a){
b的执行代码
a()
}

b()

当执行b函数时,会先执行b中的代码,然后再执行a()函数。其实很好理解,函数的参数可以是任何对象,基本的数据类型是对象,json是对象,函数也是对象,所以函数也是可以作为一个参数传递的。
关于回调函数的讲解可以查阅相应资料,个人认为这种类型的参数对于解决本文的问题是不可取的,但是对于理解函数很有帮助。

  • promise对象与deferred对象。
    promise对象的概念很早就出现了,只不过ES6才将其写入标准语法,统一了用法,具体可参考阮一峰大神的ES6语法入门
    不过promise对象的思想很重要,但是具体实现个人认为,从代码应用角度来说,不需要深究,而应该使用更优雅的async。它有它的局限,就是即使我们可以用.then()的方式,用链式语法很优雅地执行异步语法,但是两个then()函数之间的数据传递,还是需要一个个抛出去给下一个方法,这种方式还是类似于回调函数传参的方式,具体内容可以将回调函数、promise都看一遍,就能发现其中函数之间传递参数时的相似之处。
    总结一下,promise最大的好处是把形如回调地狱的一系列代码,改造成链式语法,至于原理,自行学习。
    个人理解,deferred对象和promise对象的思想是一致的:deferred对象和promise对象中记录着事件操作的结果,当我得到某个结果后,手动的操作对象中的api,来更改对象的状态,从而来标识其中事件的状态。
    在最近这次项目中,笔者使用了deferred对象,而不是promise对象主要考虑了两点:
    1)deferred对象在jq 1.5版本之后就实现了,浏览器兼容性更好,目前在火狐42与谷歌55(或者56)均没有问题。
    2)deferred对象不知可以操作异步函数,普通的js函数也可以操作。
    代码示例:
$.when(promiseUploadAvatar(file)).done(function () {
         ……逻辑代码
    })

function promiseUploadAvatar() {
    var dfd = $.Deferred();
    $.ajax({
        type:'post',
        url: avatarImportUrl
        success:function (result) {
            ……逻辑代码
            dfd.resolve();
        },
        error:function () {
          ……逻辑代码
            dfd.reject();
        }
    });
    return dfd.promise()
}

代码效果:等待异步操作promiseUploadAvatar()函数执行完毕后,才会执行.done()中的代码
代码解析:promiseUploadAvatar返回的是一个Deferred对象,dfd是实例化对象,dfd.promise()一定要和前面说的promise对象区别开,虽然有的地方也可能叫deferred的promise对象,但是和ES6中的promise并不是一回事。这是jq的defferred对象中自己封装的函数,可以理解为deferred promise对象,这个方法的作用是阻止其他代码来改变这个dfd对象,可以理解为这是deferred对象的只读版。
var dfd = $.Deferred();——实例化一个deferred对象,命名为dfd。
dfd.resolve()——告诉dfd对象,事件已经完成了,状态置为“已完成”
dfd.reject()——告诉dfd对象,事件出问题了,状态置为“已失败”
return dfd.promise()——把对象返回出去,当 $.when()调用时,告诉外面,这个事件究竟是什么情况,而 $.when()就是在等待dfd对象的状态,什么时候拿到dfd对象的状态了,什么时候执行后面的方法。
本例 $.when()后面的链式语法用的done(),意思是只要拿到dfd对象的状态是“已完成”,就会执行后面的代码,理论上,当状态置为“已失败”时,会执行.fail()中的代码。(但是在我这貌似没生效,因为用不到,所以也没有深究)
deferred对象相关知识,推荐阮一峰deferred博客.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

中二少年学编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值