首先回顾一下jQuery的deferred对象:
jQuery的deferred对象
关于Promise的进化史
在jQuery1.4中,还没有promise这个概念,写一个ajax,就得写回调函数,就像这样:
$.get('/myData', {
success: onSuccess,
failure: onFailure,
always: onAlways
})
到了jQuery1.5+之后,有了promise,就可以给ajax 的get返回的就是一个promise对象(我这样理解不知道对不对)
然后代码的形式就变成了这样:
var promise = $.get('/myData');
promise.done(onSuccess);
promise.fail(onFailure);
promise.always(onAlways);
这样的好处是Promise对象和EventEmitter对象一样,可以向同一事件绑定任意多的处理器。
promise就是deferred
或者说是用deferred就可以生成一个promise对象
var prompt = new $.Deferred();
$('#playGame').focus().on('keypress', function(e) {
var Y = 121,
N = 110;
if (e.keyCode === Y) {
prompt.resolve();
} else if (e.keyCode === N) {
prompt.reject();
} else {
return false; // they must choose!
}
});
prompt.done(function() {
console.log('Starting game...');
});
prompt.fail(function() {
console.log('No game today.');
});
prompt.always(function() {
console.log('A choice was made');
});
输入y就会打印
输入n就会打印
即,每次调用promtDeferred对象,都会先运行一下always(),再运行done或者fail(调用promt.resolve()就是done,reject就是fail)
同时测试结果显示表明,调用了一次之后就不管用了。也就是说Promise对象只能执行或拒绝一次,之后就失效了。期间Promise对象会一直保持挂起状态。
这里我们可以调用promt.state()方法,确实是“pending”
这里我打印一下promt对象的属性和方法,就可以看到promise的方法有always,done,fail,notify…..
生成一个纯promise对象
上面的图,我们可以看到promt有一个promise()方法,没错,就是调用这个方法来生成纯promise对象。
promise对象和Deferred对象的区别是,没有resolve和reject方法。promise的promise也是指向自己。
因此可以考虑这是一个封装:每个deferred对象都含有一个promise对象,每个promise对象都代表着一个deferred对象。有了deferred对象,就可以控制其状态,有了promise对象就可以读取其状态。
jQuery中的Promise对象
还是参见上面的图,很多方法都没有介绍
首先,说明的是在jQuery中,不仅只有Ajax函数(.ajax,.get, .post)可以返回Promise对象,动画函数也可以返回Promise对象。
notify和progress
Promise对象接受3种回调方式:done、fail和progress。
- 执行Promise对象时,运行的是done回调;
- 拒绝Promise对象时,运行的是fail回调;
- 对于挂起状态的Deferred对象调用notify,运行的是progress回调;
when
when相当于Promise执行情况的逻辑与运算符(AND)。一旦给定的所有Promise均已执行,就立即执行when产生的Promise对象;
或者,一旦给定的任意一个Promise被拒绝,就立即拒绝when产生的Promise。
pipe
pipe是jquery1.6+提供的方法。
pipe是promise上的方法,pipe对象也是promise对象。
初始Promise对象的行为一直级联到管道末尾的promise对象。
Promise对象的使用
用Promise对象代替回调函数
deferreCallback = function(deferred) {
return function(err) {
deferred.reject(err)
} else {
deferred.resolve(Array.prototype.slice.call(arguments, 1));
}
}
var fileReading = new $.Deferred();
fs.readFile(filename, 'utf8', deferreCallback(fileReading));
文件读取是一个耗时的工作,我们将Priomise对象代替回调函数,当文件读取成功就执行deferred.resolve,失败就执行deferred.reject。