JavaScript异步编程(三) Promise和Deferred对象
Promise和Deferred对象
现在jQuery中所有的Ajax函数多会返回Promise对象。
Promise对象代表一项有两种可能结果(成功或失败),并持有多个回调。
以前:
$.get(url, {
success: onSuccess,
failure: onFailure,
always: onAlways
});
现在
var promise = $.get(url);
promise.done(onSuccess);
promise.fail(onFailure);
promise.always(onAlways);
变化:现在是在触发Ajax调用之后再附加回调的。
好处:实现封装。Ajax调用部分的代码分离,不再像以前一样去处理之后的事情。
Promise对象也和EventEmitter对象一样,允许向同一个事件绑定任意多的处理器;
Promise对象最大优势在于,可以从现有Promise对象派生出新的Promise对象。
生成Promise对象
Deferred是Promise的超集,它比Promise多了一项关键特性:可直接触发。
纯Promise实例只允许添加多个调用,且必须由其他东西来触发这些调用。
而使用resolve和reject方法均可触发Deferred对象。
var deferred = new $.Deferred();
deferred.always(function() {…});
deferred.done(function() {…});
deferred.fail(function() {…});
$(‘#palyGame’).focus().on(‘keypress’, function(e) {
var Y = 121, N = 110;
if(e.keyCode === Y) {
deferred.resolve();
} else if(e.keyCode ===N ) {
deferred.reject();
} else {
return false;
}
});
Promise 只能执行或拒绝一次,之后就失效了。
我们断言,Promise 对象会一直保持挂起状态,直到被执行或拒绝。
生成纯Promise对象
Deferred对象调用promise()方法即可;
每个Deferred对象都含有一个Promise对象,而每个Promise对象都代表着一个Deferred对象。有了Deferred对象,就可以控制其状态,而有了纯Promise对象,只能读取其状态及附加回调。
执行或拒绝Deferred对象时,提供的任何参数都会转发到相应的回调。
进度通知
var nanowrimoing = $.Deferred();
var wordGoal = 20;
nanowrimoing.progress(function(wordCount) {
var percentComplete = Math.floor(wordCount/wordGoal *100);
$('#indicator').text(percentComplete + '% complete');
});
nanowrimoing.done(function() {
$('#indicator').text('Good job!');
});
$('#editor').on('keypress', function() {
var wordCount = $(this).val().length + 1;
if(wordCount >= wordGoal) {
nanowrimoing.resolve();
}
nanowrimoing.notify(wordCount);
});
Promise 对象接受3 种回调形式:done、fail 和progress。
执行Promise 对象时,运行的是done 回调;
拒绝Promise对象时,运行的是fail 回调;
对处于挂起状态的Deferred 对象调用notify 时,运行的是progress 回调。
Promise对象的合并
$.when();
管道连接
JavaScript无法便捷地执行一系列异步任务,一个主要原因是无法再第一个任务结束之前就向第二个任务附加处理器。
var getPromise = $.get('/query');
getPromise.done(function(data) {
var postPromise = $.post('/search', data);
});
// 现在我们想给postPromise 附加处理器……
在GET 操作成功之前我们无法对postPromise对象绑定回调,
因为这时postPromise 对象还不存在。
解决方案:
var getPromise = $.get('/query');
var postPromise = getPromise.pipe(function(data) {
return $.post('/search', data);
});
pipe 最多能接受3个参数,它们对应着Promise 对象的3 种回调类型:done、fail 和progress。