Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。
Promise的状态
状态有三种:pending、resolved和rejected。新建的Promise状态为pending,状态改变只有两种可能,要么从pending变为resolved,要么从pending变为rejected,状态的改变不受外界的影响,且状态转变后就不再改变。
Promise的缺点
Promise的构造函数接受一个函数作为参数,而传入的这个函数又有两个参数分别为resolve和reject,这两个参数是JavaScript引擎提供的用来转变Promise状态的函数。
resolve函数将Promise的状态由Pending转换成Resolved,而reject函数是从Pending状态转换成Rejected。它们都可以在转换状态的同时,传递参数(如异步操作成功的结果或失败的原因)出去到对应的回调函数。
然后利用then方法去定义Resolved和Rejected的回调函数。
var p = new Promise(function(resolve, reject) {
// do something
// ...
// 转变Promise的状态
resolve('ok');
});
// 定义对应状态下的回调函数
p.then(function(msg) {
console.log(msg);
}, function(err) {
console.error('出错了');
});
Promise.prototype.then()
then方法用来定义Promise状态改变时的回调函数,它可以传入两个参数,第一个参数为Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。它的返回是一个新的Promise实例,所以可以在该方法后再调用一个then方法。
var p = new Promise(function(resolve, reject) {
var r = Math.random() * 10;
console.log(r);
if(r > 5) {
resolve('big enough');
} else {
reject('too small');
}
});
// 调用第一个then方法
p.then(function(msg) {
console.log('第一个then方法:' + msg);
return 'first ok';
}, function(error) {
console.error('第一个then方法:' + error);
return 'first fail';
}).then(function(msg) { // 链式调用第二个then方法
console.log('第二个then方法:' + msg);
}, function(error) {
console.error('第二个then方法:' + error);
});
请注意,这里前一个then方法所定义的回调函数里的返回值,会被这个then方法返回的新的Promise实例 传入下一个then方法所定义的回调函数中。
Promise.prototype.catch()
catch方法用来定义Promise状态转变为Rejected的回调函数,和then(null, rejectFunc)是一样的,它的返回也是一个新的Promise实例。
var p = new Promise(function(resolve, reject) {
// do something
// ...
reject('I have failed!');
});
p.catch(function(error) {
console.error(error);
});
一般情况下,鼓励用then方法去定义Resolved状态的回调函数,用catch方法去定义Rejected状态的回调函数。
Promise的错误比较特殊,如果没有用then或者catch方法去指定错误处理的回调函数,那么其抛出的错误并不会被外层捕获。
var p = new Promise(function(resolve, reject) {
// do something
// ...
return x;
});
// 如果删除catch方法的调用,将不会报错(chrome浏览器除外)
p.catch(function(error) {
console.error(error);
});
Promise的错误具有“冒泡”的性质,链式调用时前面的错误直至被捕获前,会一直冒泡到后面的catch方法。
var p = new Promise(function(resolve, reject) {
// do something
// ...
return x;
});
p.then(function(msg) {
console.log(msg);
}).catch(function(error) {
// 捕获前面两个Promise实例的错误
console.error(error);
});
Promise.resolve()
resolve方法可以将传入的参数转换成Promise实例。根据参数的不同处理的情况也不一样。
Promise.reject()
reject方法会返回一个状态为Rejected的Promise实例,其参数用法和Promise.resolve相似。
Promise.all()
all方法接受一个数组(或具有iterator接口的数据结构)作为参数,其元素均为Promise实例(如果不是会先用Promise.resolve方法先转为Promise实例),把这些Promise实例进行组合生成一个新的Promise实例并返回。
var p = Promise.all([p1, p2, p3]);
p的状态会由p1、p2和p3的状态来决定。
function getPromise(num) {
return new Promise(function(resolve, reject) {
var r = Math.random() * 10;
var result = {
number: num,
value: r
};
if(r > 5){
resolve(result)
} else {
reject(result);
}
});
}
var p1 = getPromise(1),
p2 = getPromise(2),
p3 = getPromise(3);
var p = Promise.all([p1, p2, p3]);
p.then(function(results) {
console.log(results);
});
p.catch(function(reason) {
console.error(reason);
});
Promise.race()
race方法和all方法一样,也是将多个Promise包装成一个新的Promise实例,只是新的Promise实例的状态取决于子Promise的规则不同。
只要p1、p2和p3其中一个Promise率先改变状态,则p就会跟着改变它的状态,并且率先改变状态的Promise的返回值会传递到p的回调函数中。
function getPromise(num) {
return new Promise(function(resolve, reject) {
var r = Math.random() * 10;
var result = {
number: num,
value: r
};
if(r > 5){
resolve(result)
} else {
reject(result);
}
});
}
var p1 = getPromise(1),
p2 = getPromise(2),
p3 = getPromise(3);
var p = Promise.race([p1, p2, p3]);
p.then(function(result) {
console.log(result);
});
p.catch(function(reason) {
console.error(reason);
});