从心认识ES6|Promise对象
一、什么是Promise
Promise是一个优秀的异步编程解决方案,它是一个对象,用来获取异步操作的消息。Promise具有两个重要的特点:
1.对象的状态不受外界的影响,有三种状态分别是:pending(进行中),fulfilled(已成功),rejected(已失败),只有异步操作的结果才能改变其状态。
2.一旦状态改变,之后就不会再改变。状态改变只有pending->fulfilled和pending->rejected两种。一旦改变发生状态就凝固,即使再添加回调函数也是没有用了。
Promise也是有缺点的,主要是以下几点:
1.无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2.如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
3.当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
二、基本用法
创造Promise实例:
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){ //由JS引擎提供,不用自己部署,就是不用自己声明
resolve(value);
} else {
reject(error);
}
});
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
一个简单的Promise对象实例:
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('resolved.');
});
console.log('Hi!');
// Promise
// Hi!
// resolved
promise实例在被创建时就是立即执行,所以先输出Promise,而.then是promise执行完的回调,所以后输出resolved。
Promise实现多重异步操作:
在声明的时候,Promise传递的参数函数会立即执行,因此Promise使用的正确姿势是在其外层再包裹一层函数。在只有一重的异步操作时,Promise似乎没什么优势,而在多重的异步实现中就大不一样了。下面是一个例子中,如果没有采用Promise,回调地狱是不可避免的,而使用Promise就可以完美的管理几个相互依赖的函数的顺序。
//第一个异步任务
function run_a(){
return new Promise(function(resolve, reject){
//假设已经进行了异步操作,并且获得了数据
resolve("step1");
});
}
//第二个异步任务
function run_b(data_a){
return new Promise(function(resolve, reject){
//假设已经进行了异步操作,并且获得了数据
console.log(data_a);
resolve("step2");
});
}
//第三个异步任务
function run_c(data_b){
return new Promise(function(resolve, reject){
//假设已经进行了异步操作,并且获得了数据
console.log(data_b);
resolve("step3");
});
}
//连续调用
run_a().then(function(data){
return run_b(data);
}).then(function(data){
return run_c(data);
}).then(function(data){
console.log(data);
});
/*运行结果
step1
step2
step3
*/
Promise实现链式调用的流程图如下
三、Promise.prototype.then()
其实在上面我们已经介绍了Promise的then方法,这是定义在Promise.prototype原型上的方法。then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL);
}).then(function funcA(comments) {
console.log("resolved: ", comments);
}, function funcB(err){
console.log("rejected: ", err);
});
上面的例子中,getJSON是一个采用Promise封装的方法,第一个then返回一个新的Promise对象,第二个then只有等到这个新的Promise状态发生改变才会执行。
四、Promise.prototype.catch()
和then方法一样,catch也是Promise.prototype原型上的方法,用于指定发生错误时的回调函数。如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误。
getJSON('/post/1.json').then(function(post) {
return getJSON(post.commentURL);
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误
});
在一般情况下,虽然then方法可以接受两个回调,分别对应fulfilled和rejected状态,但是更为普遍的是采用catch方法来处理rejected对应的处理。所以上面的例子中,任何的Promise抛出的错误都会被最后的catch捕获。
五、Promise.prototype.finally()
finally也是定义在Promise.prototype原型上的方法,同样返回新的Promise对象,不同的是,无论Promise的状态是变成fulfilled还是rejected,finally都会被执行。这也体现了finally方法是不能知道Promise对象的状态的。
server.listen(port)
.then(function () {
// ...
})
.catch(function(){
// ...
})
.finally(server.stop);
这个例子中,无论前面是执行了then还是catch,都会执行后面的finally。
六、Promise.all()
Promise.all是将很多个Promise对象包装成一个Promise对象。
const p = Promise.all([p1, p2, p3]);
例子中,只有p1, p2, p3状态都变成fulfilled,p的状态才会变成fulfilled并接受p1, p2, p3回调组成的数组;否则p的状态就是rejected并接受第一个rejected的回调。
七、Promise.race()
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
例子中,如果p1, p2, p3中有一个状态先改变,p的状态就跟着改变,而且先改变的Promise回调会传给p。
八、Promise.resolve()
用于将对象转化成Promise对象,根据传入的参数不同,执行不同的操作。
参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve
将不做任何修改、原封不动地返回这个实例。
参数是一个thenable对象
thenable对象指的是具有then方法的对象。Promise.resolve()会立即执行thenable里的then,状态变为resolved。
参数不是具有then方法的对象,或根本就不是对象
Promise.resolve方法返回一个新的Promise对象,状态为resolved。
不带有任何参数
直接返回一个Promise对象,状态为resolved。
九、Promise.reject()
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
参考:
阮一峰ES6
MDN Promise
Promise简单入门
微信扫一扫,关注“厦猿”,获取更多前端学习资料