小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
deferred对象
在jQuery
当中,存在一个deferred
延时对象,deferred对象就是jQuery的回调函数解决方案。
在当前ES6中的Promise出来后,jQuery
的deferred
的使用就少了很多,毕竟有了更好的解决方案。
不过本文主要讲述的还是deferred
。 在jquery
较高的版本中,都是已经支持deferred
对象了。
开发网站的过程中,我们经常遇到某些耗时很长的javascript操作。其中,既有异步的操作(比如ajax读取服务器数据),也有同步的操作(比如遍历一个大型数组),它们都不是立即能得到结果的。 通常的做法是,为它们指定回调函数(callback)。即事先规定,一旦它们运行结束,应该调用哪些函数。 但是,在回调函数方面,jQuery的功能非常弱。
在使用jQuery的ajax
时,可以直接在后面调用。
例子:
function getAjax() {
$.get("http://localhost:3001/goodsList")
.done(function(data){ console.log(data); })
.fail(function(){ console.log("出错啦!"); });
}
复制代码
从这个例子中就可以看到,jQuery
中Ajax
请求获取的数据可以通过链式的写法来避免造成回调地狱。
deferred实例
当然这里是直接使用$.ajax
,所以对于deferred
的使用看起来并不明显,那么接下来使用setTimeout
的一个例子来实际写一下deferred
的延迟用法吧。
在下面两个方法当中,执行random
方法之后,需要知道setTime
方法中的num改变,才能继续走下去,因为内部存在setTimeout
,所以并不确定num改变的时间:
function random() {
let randomTime = Math.random()*1000;
setTime(randomTime)
}
function setTime(randomTime) {
let num = 0;
setTimeout(()=>{
num = randomTime;
}, randomTime)
}
复制代码
同步思维
setTimeout的存在,导致异步,如果按照同步的思路会是以下写法:
function random() {
let randomTime = Math.random()*1000;
let res = setTime(randomTime)
change(res);
}
function setTime(randomTime) {
let num = 0;
setTimeout(()=>{
num = randomTime;
return num;
}, randomTime)
}
function change(num) {
console.log(`num数值改变,当前为:${num}`);
}
复制代码
但是这样肯定会出错,结局如下:
回调解决
如果是使用回调方法,可以如下编写:
function random() {
let randomTime = Math.random()*1000;
setTime(randomTime, change)
}
function setTime(randomTime,callback) {
let num = 0;
setTimeout(()=>{
num = randomTime;
callback(num);
}, randomTime)
}
function change(num) {
console.log(`num数值改变,当前为:${num}`);
}
复制代码
效果:
但是如果更加复杂的情况,就很容易写成回调地狱,一层套一层的情况。
deferred解决方式
function random() {
let randomTime = Math.random()*1000;
let res = setTime(randomTime);
res.done((result)=>{
// 返回的result并不是结果,而是方法
change(result());
}).then((val)=>{
// 可以使用.then继续走下去
console.log(val());
})
}
function setTime(randomTime) {
let num = 0;
let dfr = $.Deferred(); // 定义Deferred
setTimeout(()=>{
num = randomTime;
// 改变deferred对象的执行状态,这里可以返回num作为resolve的结果
dfr.resolve(()=>{
return num;
});
}, randomTime)
return dfr.promise();
}
function change(num) {
console.log(`num数值改变,当前为:${num}`);
}
复制代码
当前效果,已经达到和回调相同的方式,并且可以通过.then
方法持续走下去,避免产生多余的回调:
当然其实jQuery
中的deferred
还有更多的衍生方法,这里推荐阮一峰老师的教程。
参考文章: jQuery的deferred对象详解