持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
前言:今天做项目时,遇到
Promise抛出错误捕获不到的情况,然后我就去找了,阮一峰ES6入门重新学了一遍,又加深了对Promise的理解,分享给大家,望斧正!
先来看一段代码,创建一个Promise实例,状态设置为成功fulfilled
const pro = new Promise((resolve, reject) => {
resolve('我成功啦')
})
pro.then((res) => {
console.log("then: " + res);
}).catch((err) => {
console.log('catch: ' + err);
})
//运行结果//then: 我成功啦
往Promise构造函数传入一个函数,函数有两个参数:
resolve:resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功” (即从 pending 变为fulfilled),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject:reject函数的作用是,将Promise对象的状态从“未完成”变为“失败” (即从 pending 变为rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
我成功啦 通过resolve函数,传递出去,被then方法接收到,then方法第一个参数是fulfilled状态的回调函数,所以就将 我成功啦 作为参数 res 打印出 then: 我成功啦
如果传入的函数抛出错误呢?
const pro = new Promise((resolve, reject) => {
//resolve('我成功啦')
throw Error('请求超时')
})
pro.then((res) => {
console.log("then: " + res);
}).catch((err) => {
console.log("catch: " + err);
})
//运行结果//catch: Error: 请求超时
现在我要把pro对象状态改变后的结果传递出去:我用returnPromise函数将pro对象调用then或catch方法后的结果 return 出去
const pro = new Promise((resolve, reject) => {
//resolve('我成功啦')
throw Error('请求超时')
})
function returnPromise() {
return pro.then((res) => {
console.log("then: " + res);
return res
}).catch((err) => {
console.log('catch: ' + err);
return err;
})
}
returnPromise().then((res) => {
console.log('returnPromise then resolve: ' + res);
}).catch((err) => {
console.log('returnPromise catch: ' + err);
})
//运行结果 //catch: Error: 请求超时
//returnPromise then resolve: Error: 请求超时
诶,有点奇怪,抛出的错误在returnPromise内会被catch捕获到,而在外部调用后是在then方法内打印出来。
这里千万别搞混了,pro对象此时的状态是rejected,所以被catch捕获到,这很合理
解释:
Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。
pro对象调用catch方法后返回,一个新的Promise对象(这里的catch方法其实就是then方法,因此也是返回一个新的Promise对象)
解释:
then方法返回的是一个新的Promise对象(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
因此,这个新的Promise对象调用then方法而不调用catch方法,是因为其状态为fulfilled(这里我还不知道为什么是fulfilled状态)
查完原因回来了 😁
根据Promise A+规范 (注释中的数字就是规范里的序号) then方法必须返回一个新的Promise对象
promise2 = promise1.then(onFulfilled, onRejected); //2.2.7
- 如果
then方法里的两个参数onFulfilled或onRejected其中一个返回一个值x,则运行 Promise Resolution Procedure[[Resolve]](promise2, x)。
- 如果其中一个
onFulfilled或onRejected抛出异常e,则promise2必须以e为理由来进入rejected状态。
- 如果
onFulfilled不是一个函数且promise1状态为fulfilled,promise2必须是fulfilled状态,且跟promise1有着一样的value
- 如果
onRejected不是一个函数且promise1状态为rejected,promise2必须是rejected状态,且跟promise1有着一样的reason
"value” is any legal JavaScript value (including
undefined, a thenable, or a promise).“reason” is a value that indicates why a promise was rejected.
所以,pro对象调用catch方法后,catch方法return err,符合了第 1 点规则,因此,调用returnPromise()直接返回一个fulfilled状态的 Promise 对象,且参数为err
怎么让returnPromise方法调用后走catch方法呢?
在returnPromise内部调用catch方法后,返回一个rejected状态的Promise实例对象
const pro = new Promise((resolve, reject) => {
throw Error('请求超时')
})
function returnPromise() {
return pro.then((res) => {
console.log("then: " + res);
return res
}).catch((err) => {
console.log('catch: ' + err);
//return err;
return Promise.reject(err) //2.3.2
})
}
returnPromise().then((res) => {
console.log('returnPromise then resolve: ' + res);
}).catch((err) => {
console.log('returnPromise catch: ' + err);
})
//运行结果 //catch: Error: 请求超时
//returnPromise catch: Error: 请求超时
pro对象catch方法返回一个值x (这里x为Promise.reject(err),一个rejected状态的Promise对象) 则执行[[Resolve]](promise, x),并把新的promise对象的状态,置为跟x一样的rejected状态
那么如果在then方法内加上rejected状态的回调函数会怎么样呢?
前面我们说:Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。
const pro = new Promise((resolve, reject) => {
throw Error('请求超时')
// resolve('我成功啦')
})
function returnPromise() {
return pro.then((res) => {
console.log("then: " + res);
return res
}).catch((err) => {
console.log('catch: ' + err);
// return err;
return Promise.reject(err)
})
}
returnPromise().then((res) => {
console.log('returnPromise then resolve: ' + res);
}, (rej) => {
console.log('returnPromise then reject: ' + rej);
}).catch((err) => {
console.log('returnPromise catch: ' + err);
})
//运行结果 //catch: Error: 请求超时
//returnPromise then reject: Error: 请求超时
结果是在then方法内rejected状态的回调函数捕获到错误