用Promise组织程序
一、Promise基本用法
很多文章介绍Promise给的例子是这样的:
new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('POST', location.href, true);
xhr.send(null);
xhr.addEventListener('readystatechange', function(e){
if(xhr.readyState === 4) {
if(xhr.status === 200) {
resolve(xhr.responseText);
} else {
reject(xhr);
}
}
})
}).then(function(txt){
console.log();
})
一定会有小朋友好奇,说尼玛,这不是比回调还恶心?
这种写法的确是能跑得起来啦……不过,按照Promise的设计初衷,我们编程需要使用的概念并非"Promise对象",而是promise函数,凡是以Promise作为返回值的函数,称为promise函数(我暂且取了这个名字)。所以应该是这样的:
function doSth() {
return new Promise(function(resolve, reject) {
//做点什么异步的事情
//结束的时候调用 resolve,比如:
setTimeout(function(){
resolve(); //这里才是真的返回
},1000)
})
}
如果你不喜欢这样的写法,还可以使用defer风格的promise
function doSth2() {
var defer = Promise.defer();
//做点什么异步的事情
//结束的时候调用 defer.resolve,比如:
setTimeout(function(){
defer.resolve(); //这里才是真的返回
},1000)
return defer.promise;
}
总之两种是没什么区别啦。
然后你就可以这么干:
doSth().then(doSth2).then(doSth);
这样看起来就顺眼多了吧。
其实说简单点,promise最大的意义在于把嵌套的回调变成了链式调用(详见第三节,顺序执行),比如以下
//回调风格
loadImage(img1,function(){
loadImage(img2,function(){
loadImage(img3,function(){
});
});
});
//promise风格
Promise.resolve().then(function(){
return loadImage(img1);
}).then(function(){
return loadImage(img2);
}).then(function(){
return loadImage(img3);
});
后者嵌套关系更少,在多数人眼中会更易于维护一些。
二、Promise风格的API
在去完cssconf回杭州的火车上,我顺手把一些常见的JS和API写成了promise方式:
function get(uri){
return http(uri, 'GET', null);
}
function post(uri,data){
if(typeof data === 'object' && !(data instanceof String || (FormData && data instanceof FormData))) {
var params = [];
for(var p in data) {
if(data[p] instanceof Array) {
for(var i = 0; i < data[p].length; i++) {
params.push(encodeURIComponent(p) + '[]=' + encodeURIComponent(data[p][i]));
}
} else {
params.push(encodeURIComponent(p) + '=' + encodeURIComponent(data[p]));
}
}
data = params.join('&');
}
return http(uri, 'POST', data || null, {
"Content-type":"application/x-www-form-urlencoded"
});
}
function http(uri,method,data,headers){
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method,