Promise

Promise的含义

Promise是异步编程的一种解决方案,比传统的解决方案----回调函数和事件----更合理且更强大。所谓的Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个一步操作)的结果。从语法上来说,promise是一个对象,从他可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同种的方法进行处理。有了Promise对象就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。

Promise对象有以下两个特点:

1、对象的状态不受外界影响。Promise对象代表一个异步操作,有3种状态:Pending(进行中)、Fulfilled(已成功)和Rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。(promise:英译“承诺”,即其他手段无法改变)。

2、一旦状态改变就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变只有两种可能:从Pending变为Fulfilled和从Pending变为Reject。只要这两种情况发生,状态就凝固了,不会再变,而是一直保持这个结果,这是就称为Resolved(已定型)。就算改变已经发生,再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同。事件的特点是,如果错过了他,再去监听是得不到结果的。

Promise的缺点

1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。

2、如果不设置回调函数,Promise内部跑出的错误不会反应到外部。

3、当处于Pending状态时,无法得知目前进展到了哪一个阶段(刚刚开始还是即将完成)

基本用法

Promise实例

var promise = new Promise (function (resolve, reject)) {
    // ... some code 
    if(/* 异步操作成功 */){
        resolve(value)
    } else {
        reject(error)
    }
}
//第一种写法
promise.then( function( result ) {
        // result ==上面的value   
}).catch(function (error){
        // error==上面的error
})
或者
promise.then( result => console.log(result))
.catch( error => console.log(error ))
//第二种写法
promise.then(function( result ) {
        // result ==上面的value   
},function (error){
        // error==上面的error
})

promise

注意:调用resolve或reject并不会终结Promise的参数函数执行。一般来说,调用resolve或reject以后,Promise的使命就完成了,最好在他们前面加上return,这样就不会产生意外。

new Promise((resolve,reject) =>{
    resolve(1);
    console.log(2);
}).then(r => {
    console.log(r);
});
//2
//1
new Promise((resolve,reject) =>{
    return resolve(1);
    console.log(2);
}).then(r => {
    console.log(r);
});
//1

注意:如果p1和p2都是Promise的实例,但是p2的resolve的方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作的。(p1的状态就会传递给p2);

var p1 = new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('fail')),3000);
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(() => resolve(p1,3000));
})
p2.then(r=>console.log(r)).catch(r=>console.log(r));
//Error:fail

Promise.prototype.then()

Promise实例具有then方法,即then方法是定义在原型对象Promise.prototype上的。then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Reject状态的回调函数。Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:

job1.then(job2).then(job3).catch(handleError);
//其中,job1、job2和job3都是Promise对象。

Promise.prototype.catch()

Promise.prototype.catch()方法是.then(null,rejection)的别名,用于指定发生错误时的回调函数。

p.then((val) => console.log("fulfilled:",val)).catch((err) =>console.log('rejected',err));
//等同于
p.then((val) => console.log("fulfilled:",val)).then(null,(err) =>console.log('rejected',err));

注意:reject方法的作用等同于抛出的错误。如果Promise状态已经resolved,再抛出出错误是无效的。

一般来说不要在then方法中定义Rejected状态的回调函数(即then的第二个参数),而应总是使用catch方法。

Promise.all()

除了串行执行若干异步任务外,Promise还可以并行执行异步任务。

试想一个页面聊天系统,我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是可以并行执行的,我们可以用Promise.all()实现。

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.all([p1, p2]).then(function (results) {
    console.log(results); // 获得一个Array: ['P1', 'P2']
});

Promise.race()

有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
    console.log(result); // 'P1'
});

由于p1执行较快,Promise的then()将获得结果'P1'p2仍在继续执行,但执行结果将被丢弃。

Promise.done()

无论Promise对象的回调链以then方法还是catch方法结尾,只要最后一个方法抛出错误,都有可能无法捕捉到(因为Promise内部的错误不会冒泡到全局)。为此,我们可以提供一个done方法,他总是处于回调链的尾端,保证抛出任何可能出现的错误。

asyncFunc().then(f1).catch(r1).then(f2).done();
//他的实现代码
Promise.prototypr.done = function (onFulfilled, onRejected) {
    this.then(onFulfilled, onRejected).catch(function (reason) {
        //抛出一个全局错误
        setTimeout(() => {throw reason },0);
     });
};

done方法可以像then方法那样使用,提供Fulfilled和Rejected状态的回调函数,也可以不提供任何参数。但不管怎样,done方法都会捕捉到任何可能出现的错误,并向全局抛出。

Promise.finally()

finally方法用于指定不管Promise对象最后状态如何都会执行的操作。它与done方法的最大区别在于,他接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。

server.listen(0).then(function (){
    //return test
}).finally(server.stop);

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐