前言
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
参考文章:
Promise 对象 - ECMAScript 6入门 (ruanyifeng.com)
Promise - JavaScript | MDN (mozilla.org)
基础知识
三种状态
pending(进行中)fullfilled(已成功)rejected(已失败)
Promise的状态改变只有两种
- 从
pending到fullfilled - 从
pending到rejected
假如你已经直到自己目前是什么状态(resolve还是reject),那么这时候,只要你then()了,那么Promise对象就会立即调用他的回调函数
基本使用
const promise = new Promise(function(resolve,reject){
if(成功){
resolve()
}else{
reject
}
})
首先观察代码,你可以发现
Promise是new出来的,那么,大胆猜测,Promise就是一个对象- 发现
Promise里面含有参数,说明,Promise对象的构造函数接受了一个参数 - 这个参数是一个函数,并且这个函数也接受两个参数,这两个参数(·
resolve·reject)也是函数(有点套娃行为) - 当时这个
resolve,和reject他们其实是内置的一个函数,不需要我们做什么,只需要调用即可 resolve:当我们状态由pending变为fullfied时执行reject:当我们状态由pending到rejected- 这时候我们的
promise,就是一个Promise的实例
那么我们使用then,来获取他们状态的回调
promise.then(()=>{
//成功
},()=>{
//失败
})
你可以知道
then方法也是,具有两个参数,两个参数都是函数- 分别表示的时
resolve和reject的回调
执行顺序
Promise是进行异步操作的,结合我们的eventLoop,其实我们可以大概知道,就是Promise之后执行的回调,首先会变为一个message进入我们的queue,等我们的stack全部都处理完成了,我们的message才会被shift()出来,那么回调才会被执行
let promise = new Promise(function(resolve,reject){
console.log("hello")
resolve();
})
promise.then(function(){
console.log("summer")
})
console.log("你好")
//hello
//你好
//summer
让我们来分析一下
- 在
js中函数是很重要的,浅看一下,没有函数,很好,那么就往下执行 - 首先,遇到了
Promise对象,那么按照顺序执行这个hello,并且我知道了,当前Promise的状态为fullfilled - 这时因为回调函数是异步的,并且我当前的
stack里面是非空的,所以,回调函数作为一个参数进入queue里面 - 然后执行输出
你好 - 这时候同步操作处理完了,这时候去处理这个回调,输出
summer
参数问题
如果你的resolve或者reject函数含有参数,那么这个参数会带给回调函数
现在来看一下这段代码
const p1 = new Promise(function(resolve,reject){
//操作
reject()
})
const p2 = new Promise(function(resolve,reject){
//
resolve(p1)
})
p2.then(result=>console.log(result))
.catch(error=>{
console.log(error)
})
现在我们可以知道,p1和p2都是Promise的实例对象
P1是reject,p2是resolve- 但是在
p2里,我们发现,他将p1作为参数,传给了resolve - 那么也就是,我
p1的状态会传给p2,p1的状态会就觉得p2的状态 - 就算你现在
p2是resolve的,但是因为我p1是reject,那么,我的p2也只能是reject
promise.then()
接受两个可选参数,分别表示
resolve和reject的回调
但是:我们需要知道,每次then他是生成了一个新的Promise对象,和原来那个Promise是没有关系的
正是因为这个原因,我们才可以使用Promise的链式写法
约定:
- 使用
then,第一个回调的返回值会作为第二个回调的参数 - 那么也即是,假如你第一个回调返回的是一个
Promise,那么你的状态会直接影响下一个回调的状态
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
myPromise
.then(handleResolvedA)
.then(handleResolvedB)
.then(handleResolvedC)
.catch(handleRejectedAny);
Promise.catch()
Promise对于错误的处理
其实它就相当于Promise.then(null,(error)=>{})
Promise的错误处理,如果没有处理,那么会一直往下去,知道遇到catch捕获
所以,这也就是为什么,我们很少在Promise.then()里面传入两个回调函数的原因
const promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise.catch(function(error) {
console.log(error);
});
// Error: test
在Promise里其实抛出错误和reject是一回事
所以,一般情况下,我们Promise后面都会跟着一个catch方法,用于捕获错误
如果我们不对错误进行捕获,那么试想一下,他这个错误会一直存在,然后到他的调用者也会有
其实catch返回的也是一个Promise对象,所以,在catch里面才会可以使用then()方法
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// 下面一行会报错,因为x没有声明
resolve(x + 2);
});
};
someAsyncThing()
.catch(function(error) {
console.log('oh no', error);
})
//捕获以后,会依然是一个Promise对象,然后再次进行
.then(function() {
console.log('carry on');
});
这样我们就可以看出,其实Promise是相互独立的,所以,我们才会有链式
catch:只会捕获,在他之前的错误,对于他之后的错误,这能说,这个catch是管不了了
Promise.finally()
无论我的状态是什么(
fullfilled还是reject)我们都会执行的操作
教程里面说:finally其实是一种特殊的then
为什么?
我的理解是:因为finally总是会有一个返回值
// resolve 的值是 undefined
Promise.resolve(2).then(() => {}, () => {})
// resolve 的值是 2
Promise.resolve(2).finally(() => {})
// reject 的值是 undefined
Promise.reject(3).then(() => {}, () => {})
// reject 的值是 3
Promise.reject(3).finally(() => {})
这样我们就可以看出,其实finally就是会返回上次你的Promise的返回值
那么也就是,我不管你错不错误,我都会将它返回出去了
总结
Promise还有一些其他的方法,后续慢慢补充吧
其实之前我一直都没怎么用Promise,因为之前只用过async和await,其实我现在感觉,await是promise.then()的一种封装,因为await后面一定是一个Promise实例。