继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Promise入门

梁凤波
关注TA
已关注
手记 27
粉丝 4318
获赞 1744

一、生命周期

Promise生命周期中有三个状态

  • 进行中(pending)
  • 成功(resolved)
  • 拒绝(rejected)

pending代表promise进入未处理(处理中)状态,一旦promise生命周期结束就会变为:resolved和rejected状态其中之一,resolved代表处理成功,rejected代表处理被拒绝;而且Promise一旦状态改变就不会变,promise改变状态的结果只有2种可能:

pending => resolved // 成功
pending => rejected // 失败

二、创建Promise

可以使用Promise构造函数创建Promise,构造函数接收2个参数:

  • resolve() 处理成功下调用的返回函数
  • reject() 处理拒绝下调用的返回函数
const fs = require('fs');

let handler = new Promise((resolve, reject) => {

    fs.readFile('./order.js', {encoding: 'utf8'}, (err, contents) => {
        // 当发生错误时,使用reject方法抛出错误
        if (err) {
            reject(err);
            return;
        }

        // 当成功执行后,执行resolve方法
        resolve(contents)
    })
})

三、处理Promise

创建的Promise执行完且改变状态后,then() 方法会监听其状态处理结果,接收2个参数:

  • 第一个参数接收的是 resolve() 处理成功函数的回调。
  • 第二个参数接收的是 reject() 处理拒绝函数的回调。
// 接上面的handler方法

// 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
// 第一个参数是回调resolve方法 [可选]
// 第二个参数是回调reject方法 [可选]
handler.then(res => {
    // success
    console.log(res);

}, err => {
    // error
    console.log(err);
})

还有一个方法是 catch() 方法,这个方法是单独接收 reject() 拒绝函数的回调,结合 then() 方法,我们可以这样写:

handler.then(res => {
    // success
    console.log(res);
    
}).catch(err => {
    // error
    console.log(err);
})

四、链式Promise

当在promise链式中then()中触发return返回另外一个promise,只有当这个promise是成功执行了才会执行下一步promise链式操作,反之其中发生拒绝状态,那么下一个promise异步操作永远不会执行。

let p1 = Promise.resolve('p1');
let p2 = Promise.resolve('p2');
let p3 = Promise.reject('p3 is error');
let p4 = Promise.resolve('p4');

p1.then(res => {
    console.log(res); // p1
    return p2;
}).then(res => {
    console.log(res); // p2
    return p3;
}).then(res => {
    console.log(res); // error 不会执行到这步
    return p4;
}).then(res => {
    console.log(res); // 不执行
}).catch(err => {
    console.log(err); // 获取到p3错误,p3 is error 
    // 解释:因为p3返回的是错误状态,p4后面就不执行了
})

四、Generator与链式Promise结合

上面的链式操作非常不优雅,我们可以使用迭代器优化代码,如下:

let p1 = Promise.resolve('p1');
let p2 = Promise.resolve('p2');
let p3 = Promise.reject('p3 is error');
let p4 = Promise.resolve('p4');

function* handlerPromise() {
    yield p1.then(res => { console.log(res) });

    yield p2.then(res => { console.log(res) });

    yield p3.catch(err => { console.log(err) });

    yield p4.then(res => { console.log(res) });
}

let handler = handlerPromise();

handler.next().value;
handler.next().value;
handler.next().value;
handler.next().value;

/**
 * 输出:
 * p1
 * p2
 * p4
 * p3 is error
 */

五、Promise.all()

Promise.all()方法可以接收一个元素为 Promise 对象的数组作为参数,当这个数组里面所有的 Promise 对象都变为 resolve 时,该方法才会返回。

// 情景一:promise都变为resolve状态
let p1 = Promise.resolve(1);
let p2 = Promise.resolve(2);

Promise.all([p1, p2]).then(res => {
    console.log(res); // [1, 2]
})

// 情景二:promise其中变为reject状态
let p1 = Promise.resolve(1);
let p2 = Promise.reject(2);

Promise.all([p1, p2]).then(res => {
    console.log(res); // not data...
    
}).catch(err => {
    console.log(err) // 捕获到错误
})

六、Promise.race()

Promise.race()方法和Promise.all()方法接收的参数一样,接收一个可迭代对象,比如数组,唯一的区别就是,Promise.race()方法返回的是该传入的对象的第一个promise结束状态后的结果,简单来说就是传入的promise对象,谁最先得出返回结果(无论是resolve或reject),就输出谁。

let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(1)
    }, 2000)
});
let p2 = Promise.reject(2);


Promise.race([p1, p2]).then(res => {
    console.log(res);
}).catch(err => {
    console.log(err); // 2
})

七、Promise优缺点

优点:

  • Promise主要解决回调地狱问题
  • 使得原本的多层级的嵌套代码,变成了链式调用
  • 让代码更清晰,减少嵌套数

缺点:

  • 无法取消Promise,一旦新建它就会立即执行,无法中途取消
  • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
  • 当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是处理中)

参考资料

  • 《深入理解ES6》-第六章 Promise与异步编程
打开App,阅读手记
6人推荐
发表评论
随时随地看视频慕课网APP