jquery 1.5后增加了deferred 对象,处理延迟。给了我们一些代码组织新的机会。
首先复习一下ajax 原理。
ajax是通过http请求远程加载数据的一种方式。异步加载,不会阻塞文件中后续代码的执行。学习的时候突然想到js引擎是单线程的,不阻塞看起来感觉是并发的样子。于是又搜索了一番,找到了一篇很对症的文章。
js单线程深入分析
看完之后我的理解是,js引擎确实是单线程的,ajax执行时,会发起一个http请求这个请求会给浏览器,浏览器有一个自己的事件队列,浏览器把它放到自己的事件队列中去,等到浏览器空闲了才会执行,当异步事件触发之后(例如xmlhttprequest 完成,回调函数触发),又会进入js执行队列,等待执行。
因为js文件中的代码在本地,远程取得数据又收到很多因素的影响(网速,页面上其他异步事件)所以一般返回回来的时候,本地js文件都执行完了。
好了,回头说说deferred
以前的ajax用法
function getCount(offerIds,callback) {
$.ajax({
url: url,
data: {
ids: ids
},
type: 'get',
dataType: 'jsonp',
success: function(json) {
if (json && json.content) {
callback(json.content);
} else {
return;
}
},
error: function() {
return;
}
})
}
这样的写法,不能把数据单独封装成一个方法,也就是说,如果我以后想用这些数据做别的事情,就只能增加callback,或者替换callback。方法不够独立,解耦做的不够好。如果拿得到返回的数据,代码的组织就会更加的灵活。
deferred给了我们这样的机会。
getCount(offeridList.join(','))
.done(function(json) {
rander(json.content);
})
.fail(function() {
rander();
});
function getCount(offerIds) {
var deferred = $.Deferred();
$.ajax({
url: url,
data: {
ids: offerIds
},
type: 'get',
dataType: 'jsonp',
success: function(json) {
if (json && json.content) {
deferred.resolve(json);
} else {
deferred.reject();
}
},
error: function() {
deferred.reject();
}
});
return deferred.promise();
}
deferred.promise() 返回一个deferred对象,只开放与改变执行状态无关的方法(比如done()方法和fail()方法),屏蔽了 resolve()和reject() 方法。
使deferred对象在ajax()外部不可以修改状态值。
这样就可以进行链式操作。done()和fail()相当于success,error 方法。deferred的好处是可以执行多个done()。链式调用,按顺序执行。
deferred.resolve()的意思是,将dtd对象的执行状态从”未完成”改为”已完成”,从而立刻触发done()方法。
如果是 .ajax().done().是不用自己手动修改deferred对象状态值的。因为 .ajax()就会返回一个deferred对象。但是如果把 .ajax()抽出来成为一个方法,就不行了,只能函数内部自己用 .deferred()自己创建一个deferred对象,手动修改状态值,再return出去,实现链式调用。