JavaScript 异步编程Promise详解

1. 定义

Promise对象用于表示一个异步操作的最终完成(或者失败)及其结果值,是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理、更强大。ES6 将其写进了语言标准,统一用法,提供了原生的Promise对象。

一个Promise对象代表一个在这个Promise被创建出来时不一定已知的值,它可以把异步操作最终的成功返回值或失败原因和相应的处理程序关联起来。这样,异步方法并不会立即返回最终的值,而是会返回一个Promise

一个Promise必然处于以下几种状态之一:

  • pending:初始状态,未被兑现,也未被拒绝
  • fulfilled:已兑现,操作完成
  • rejected:已拒绝,操作失败

2. 基本使用

通过new操作符来完成Promise的实例化,需要传入一个函数作为参数。Promise的状态是私有的,只能在内部进行操作。在传入的函数中,控制Promise的状态转换是通过调用它的两个函数参数实现的,通常命名为resolve()reject()。调用resolve()将状态转换为fulfilled,调用reject()将状态转换为rejected。另外,调用reject()抛出错误

如下代码,使用new操作符实例化了一个Promise,传入了一个函数,函数有两个参数:resolve()reject()。通过简单的判断,控制Promise的状态转换。显然,当前代码执行后,应该调用resolve(),即将状态转化为fulfilled

Promise后,调用了then方法,then方法最多接收两个函数作为参数,第一个参数是状态变为fulfilled的回调函数,第二个参数是状态变为rejected的回调函数。本例中,由于Promise状态已变为fulfilled,故then方法执行第一个参数,打印出resolve()方法传来的值:'fulfilled'

new Promise((resolve, reject) => {
    const a = 1;
    if (a === 1) {
        resolve('fulfilled');
    } else {
        reject('rejected');
    }
}).then(
    fulfilledValue => console.log(fulfilledValue),
    rejectedValue => console.log(rejectedValue)
);
// fulfilled

如果稍微修改一下a的值,使Promise的状态转为rejected,那么then方法就会执行第二个参数,打印出reject()方法传来的值:'rejected'

new Promise((resolve, reject) => {
    const a = 2;
    if (a === 1) {
        resolve('fulfilled');
    } else {
        reject('rejected');
    }
}).then(
    fulfilledValue => console.log(fulfilledValue),
    rejectedValue => console.log(rejectedValue)
);
// rejected

另外,如果内部抛出错误,then方法也会执行第二个函数:

new Promise((resolve, reject) => {
    throw 'error';
}).then(null, error => console.log(error));
// error

3. 原型方法

1. Promise.prototype.then()

then()方法返回一个新的Promise,如上文所述,它最多需要两个参数:Promise成功失败的回调函数。因为Promise只能转换一次状态,所以这两个函数一定是互斥的。

then方法支持链式调用

返回的新Promise,具体情况如下,如果then中的回调函数:

(1)返回了一个,那么then返回的Promisefulfilled状态,并将返回的值作为fulfilled状态的回调函数参数值。

如下代码所示,最初的Promise状态是fulfilled,那么第一个then方法调用第一个回调函数,先打印出1,又返回了'Jack',那么该then返回的Promise也是fulfilled状态,并且将'Jack'作为第二个then方法的回调函数参数。

new Promise((resolve, reject) => {
    resolve(1);
    // reject(-1);
})
    .then(value => {
        console.log('fulfilledValue', value);
        return 'Jack';
    })
    .then(
        res => {
            console.log('fulfilledValue', res);
        },
        res => {
            console.log('rejectedValue', res);
        }
    );
// fulfilledValue 1
// fulfilledValue Jack

这里,如果把最初的Promise状态改成rejected,那么就如下代码,第一个then方法调用的是它的第二个回调函数,这个回调函数返回'Jack',是个值,那么这个then返回的就是fulfilled状态,并将返回的值作为fulfilled状态的回调函数参数值,和上文的规则完全一致。

new Promise((resolve, reject) => {
    // resolve(1);
    reject(-1);
})
    .then(
        value => {
            console.log('fulfilledValue', value);
        },
        value => {
            console.log('rejectedValue', value);
            return 'Jack';
        }
    )
    .then(
        res => {
            console.log('fulfilledValue', res);
        },
        res => {
            console.log('rejectedValue', res);
        }
    );
// rejectedValue -1
// fulfilledValue Jack

由此可见,then方法不管调用哪个回调函数,返回Promise的规则都是一致的。为了方便起见,下文中的最初Promise都设置为fulfilled状态。

(2)没有返回任何值,那么then返回的Promisefulfilled状态,并且fulfilled状态的回调函数参数值是undefined

如下代码所示,由于第一个then没有返回任何值,所以第二个then的第一个回调函数的参数是undefined

new Promise((resolve, reject) => {
    resolve(1);
    // reject(-1);
})
    .then(value => {
        console.log('fulfilledValue', value);
    })
    .then(
        res => {
            console.log('fulfilledValue', res);
        },
        res => {
            console.log('rejectedValue', res);
        }
    );
// fulfilledValue 1
// fulfilledValue undefined

(3)抛出一个错误,那么then返回的Promiserejected状态,并将抛出的错误作为fulfilled状态的回调函数参数值。

new Promise((resolve, reject) => {
    resolve(1);
    // reject(-1);
})
    .then(value => {
        console.log('fulfilledValue', value);
        throw 'Error!';
    })
    .then(
        res => {
            console.log('fulfilledValue', res);
        },
        res => {
            console.log('rejectedValue', res);
        }
    );
// fulfilledValue 1
// rejectedValue Error!

(4)返回一个是fulfilled状态的Promise,那么then返回的Promisefulfilled状态,并且将前面Promise接受状态的回调函数参数,作为返回的Promise接受状态的回调函数参数

如下代码,第一个then返回了一个fulfilled状态的Promise,那么第二个then会调用第一个回调函数,并且参数是'fulfilled'

new Promise((resolve, reject) => {
    resolve(1);
    // reject(-1);
})
    .then(value => {
        console.log('fulfilledValue', value);
        return Promise.resolve('fulfilled');
    })
    .then(
        res => {
            console.log('fulfilledValue', res);
        },
        res => {
            console.log('rejectedValue', res);
        }
    );
// fulfilledValue 1
// fulfilledValue fulfilled

(5)返回一个是rejected状态的Promise,那么then返回的Promiserejected状态,并且将前面Promise拒绝状态的回调函数参数,作为返回的Promise拒绝状态的回调函数参数

new Promise((resolve, reject) => {
    resolve(1);
    // reject(-1);
})
    .then(value => {
        console.log('fulfilledValue', value);
        return Promise.reject('rejected');
    })
    .then(
        res => {
            console.log('fulfilledValue', res);
        },
        res => {
            console.log('rejectedValue', res);
        }
    );
// fulfilledValue 1
// rejectedValue rejected

(6)返回一个是pending状态的Promise,那么then返回的Promise也是pending状态,并且它最终状态与前面Promise最终状态相同。同时,它变成最终状态执行的回调函数参数,与前面Promise变成最终状态执行的回调函数的参数相同的。

new Promise((resolve, reject) => {
    resolve(1);
    // reject(-1);
})
    .then(value => {
        console.log('fulfilledValue', value);
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('1秒后出现');
            }, 1000);
        });
    })
    .then(
        res => {
            console.log('fulfilledValue', res);
        },
        res => {
            console.log('rejectedValue', res);
        }
    );

// fulfilledValue 1
// fulfilledValue 1秒后出现

(7)如果最初的Promiserejected状态,且第一个then没有第二个函数参数,那么第二个then就会执行其第二个回调函数,并且参数为最初Promisereject中的参数。

new Promise((resolve, reject) => {
    // resolve(1);
    reject(-1);
})
    .then(value => {
        console.log('fulfilledValue', value);
    })
    .then(null, res => {
        console.log('rejectedValue', res);
    });
// rejectedValue -1

2. Promise.prototype.catch()

Promise.prototype.catch()方法用于给Promise添加拒绝处理程序。这个方法只接收一个参数:onRejected处理程序。它的行为与调用Promise.prototype.then(undefined, onRejected)相同。

如下代码,两种等价的写法。

new Promise((resolve, reject) => {
    reject('error');
}).catch(error => console.log(error));
// error
new Promise((resolve, reject) => {
    reject('error');
}).then(null, error => console.log(error));
// error

3. Promise.prototype.finally()

Promise.prototype.finally()方法用于给Promise添加onFinally处理程序,这个处理程序在Promise转换为fulfilledrejected状态时都会执行。但onFinally处理程序不知道Promise的状态是fulfilled还是rejected,所以这个方法主要用于添加清理代码

new Promise((resolve, reject) => {
    console.log('loading start...');
    const a = 2;
    if (a === 1) {
        resolve(1);
    } else {
        reject(-1);
    }
})
    .then(value => {
        console.log('fulfilled value', value);
    })
    .catch(error => console.log('error', error))
    .finally(() => console.log('loading end...'));
// loading start...
// error -1
// loading end...

4. 实例方法

1. Promise.all()

Promise.all()方法接收一个Promise可迭代类型的输入,并且返回一个Promise实例, 那个输入的所有Promiseresolve回调的结果是一个数组。简单来说,Promise.all()用于将多个Promise实例包装成一个新的Promise实例。

const promiseArray = [1, 2, 3, 4].map(item => new Promise(resolve => resolve(item)));
console.log(promiseArray);
// [ Promise { 1 }, Promise { 2 }, Promise { 3 }, Promise { 4 } ]

Promise.all(promiseArray).then(res => console.log(res));
// [ 1, 2, 3, 4 ]

2. Promise.race()

Promise.race(iterable)方法返回一个Promise,一旦迭代器中的某个Promise接受拒绝,返回的Promise就会接受拒绝

const promiseArray = [1, 2, 3, 4].map(item => new Promise(resolve => resolve(item)));
console.log(promiseArray);
// [ Promise { 1 }, Promise { 2 }, Promise { 3 }, Promise { 4 } ]

Promise.race(promiseArray).then(res => console.log(res));
// 1

3. Promise.resolve()

Promise.resolve()方法返回一个接受状态Promise对象。

Promise.resolve(1).then(res => console.log(res));
// 1

4. Promise.reject()

Promise.reject()方法返回一个带有参数的拒绝状态Promise对象。

Promise.reject(-1).then(null, res => console.log(res));
// -1

以上是本人学习所得,若有不妥,欢迎指出交流!


参考:

  • 《JavaScript高级程序设计(第4版)》
  • 「MDN」

📘📘欢迎在我的博客上访问:
https://lzxjack.top/

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火星飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值