Promise在前端开发中用的很多了,感觉好像很熟了,但真的有些细节追究起来好像又有点是是而非。
今天聊聊Promise中的then和catch,以下面这个代码片段为例,如果能正确说出打印的内容,说明已经掌握了,后面的内容就可以不用看了。
const a = new Promise((resolve, reject) => {
reject('error');
})
.then((res) => {
console.log('res', 1);
})
.then(
(res) => {
console.log('res', 2);
},
(err) => {
console.log('error', 1);
}
)
.then((res) => {
console.log('res', 3);
})
.catch((err) => {
console.log('error', 2);
});
答案是:先后打印
error 1
res 3
Promise的定义和使用方法这里就不做详细说明,主要聊聊then和catch
1. then方法
直接打印Promise对象(使用console.dir),可以看到Promise.prototype中定义了catch、finally、then方法,所以在new Promise后可以调用then、catch等方法
1.1 then方法接收的参数
then方法可以接收两个参数,一个是Promise状态为Resolved时要执行的回调函数,第二个参数是Promise状态为Rejected时要执行的回调函数。
new Promise((resolve, reject) => {
resolve(1);
}).then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
// 打印 1
由于Promise状态变成了Resolved,所以执行then中的第一个回调函数,函数的参数为resolve的值
new Promise((resolve, reject) => {
reject('error');
}).then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
由于Promise状态变成了Rejected,所以执行then中的第二个回调函数,函数的参数为reject传入的error值。
Q:
日常开发中,我们一般只会在then中传入一个Resolved状态的回调函数。那如果Promise的状态为rejected,但是其后面的then方法又没有定义第二个参数会怎么样?
A:
then会将这个rejected状态的Promise传递下去,直到被某个catch或then的第二个参数处理。后面讲到catch时再具体说明
1.2 then方法的返回
then方法会返回一个Promise对象,Promise对象的状态要根据then执行的回调中(可能是执行的第一个也可能是第二个,具体执行哪一个跟前面返回的Promise对象的状态有关,即1.1中的内容)返回的内容有关:
回调返回内容 | then方法返回结果 |
---|---|
执行的回调中抛出了一个错误 | 返回的是一个Rejected状态的Promise对象,相当于return Promise.reject(error) |
执行的回调中return了一个非Promise的值(或者没有return任何内容(undefined)) | 返回的是一个Resolved状态的Promise对象,resolve的值就是return的值 |
执行的回调中return了一个Promise对象 | 返回的就是return的这个Promise对象 |
如果then前面的Promise是reject状态,但then中第二个参数未定义 | 返回的是前面这个reject状态的Promise |
这里可以参考Promise对象解析(2)then方法
由于then方法始终会返回一个Promise对象所以then后面还可以继续调用then方法形成一个链式效果
2. catch方法
catch方法同样是Promise.prototype的定义的一个方法,用于指定Promise为Rejected状态时执行的回调
2.1 catch方法接收的参数
catch方法接收一个参数,需要传入一个函数,当前面返回的Promise的状态为rejected时,将执行catch中接收的回调函数
new Promise((resolve, reject) => {
reject('error');
}).catch((err) => {
console.log(err);
});
2.1 catch和then的关系
catch可以理解为Promise.prototype.then(undefined,rejectedCallback)的一个语法糖,
即下面两段代码是等效的
new Promise((resolve, reject) => {
reject('error');
}).then(undefined, (err) => {
console.log(err);
});
new Promise((resolve, reject) => {
reject('error');
}).catch((err) => {
console.log(err);
});
2.3catch方法的返回
既然catch是Promise.prototype.then(undefined,rejectedCallback)的一个语法糖,那么他的返回和then是一样的,它也将返回一个Promise对象,Promise对象的状态和其回调中return的内容有关,参考上面then的返回
最后来解释开头中的题目
const a = new Promise((resolve, reject) => {
reject('error'); //Promise状态变成Rejected
})
.then((res) => {
console.log('res', 1);//这里then只传入了一个回调函数,rejected状态不会执行这个回调,then方法会将当前rejected状态Promise对象返回
})
.then(
(res) => {//前面的Promise为rejected状态,此回调不执行
console.log('res', 2);
},
(err) => {//执行
console.log('error', 1);//由于这里面没有抛出错误,也没任何返回,故then方法会返回一个Resolved状态的Promise对象。resolve值为undefined
}
)
.then((res) => {//执行,因为前面的Promise状态为Resolved,这里res为undefined
console.log('res', 3);//由于这里面没有抛出错误,也没任何返回,故then方法会返回一个Resolved状态的Promise对象。resolve值为undefined
})
.catch((err) => {//前面的Promise状态为Resolved,这里的回调不会执行,catch方法最后会返回一个Resolved状态的Promise对象。resolve值为undefined
console.log('error', 2);
});