promise reject处理
function fn(a) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (a > 10) {
resolve('a大于10')
} else {
reject('a 不大于 10')
}
}, 1000)
})
}
fn(7)
.then(res => {
console.log('resolve', res);
}, err => {
console.log('reject', err)
})
.catch(err => {
console.log('err:', err);
})
// 输出:reject a 不大于 10
上述代码中fn返回一个promise,因为7<10 所以promise 走的是reject分支。
promise的then方法接收两个参数:
- 第一个是resolve函数,参数是promise抛出resolve时的参数
- 第二个参数是reject函数,参数是promise抛出reject时的参数
这里的输出结果是 reject a 不大于 10
,也就是说这里走了reject回调函数,没有走catch函数。
再来看第二种情况:
fn(7)
.then(res => {
console.log('resolve', res);
})
.catch(err => {
console.log('err:', err);
})
// 输出:err: a 不大于 10
这里我们把then函数的第二个参数(reject函数)去掉,执行结果是:err: a 不大于 10
。也就是说走了catch函数,catch捕获了reject的返回内容
结论:
- catch可以捕获reject的内容
- then函数的第二个参数(reject回调函数)与catch同时存在时,reject优先捕获,catch失效
- 建议使用catch代替reject回调函数
async 与try-catch
async function main() {
const res = await fn(7)
console.log(res);
}
main()
/*
输出:[Running] node "/Users/ccc/Documents/Coding/test/async/app.js"
(node:1311) UnhandledPromiseRejectionWarning: a 不大于 10
(node:1311) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:1311) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
*/
我们知道 fn的promise应该返回reject,async函数可以使用await等待promise的返回结果。但是这里的reject没有异常捕获,当promise返回reject时,就报错了。
所以aynnc应该配合try-catch进行异常捕获,如下:
async function main() {
try {
const res = await fn(7)
console.log(res);
} catch (error) {
console.log('err: ', error);
}
}
main()
// 输出:err: a 不大于 10
这个时候catch就可以捕获到reject的返回内容。
结论:catch可以捕获promise抛出的reject信息,async应该配合try-catch进行异常处理
async碰上async
async function main() {
try {
const res = await fn(7)
console.log('main res:', res);
return res;
} catch (error) {
console.log('main err: ', error);
throw new Error('main err...: ' + error)
}
}
async function app() {
try {
const res = await main();
console.log('app res:', res);
} catch (error) {
console.log('app err:', error)
}
}
app();
/*
输出:
main err: a 不大于 10
app err: Error: main err...: a 不大于 10
at main (/Users/ccc/Documents/Coding/test/async/app.js:20:11)
*/
可以看到先执行了main err,才执行的app函数的try里的console.log,说明async可以用await接收等待一个async函数的执行结果。
async函数中 throw new Error 就类似reject,可以在下一个流程中catch捕获到throw抛出的结果。
接下来改造main函数,就fn的参数变成11,return注释掉,app保持不变
async function main() {
try {
const res = await fn(11)
console.log('main res:', res);
// return res;
} catch (error) {
console.log('main err: ', error);
throw new Error('main err...: ' + error)
}
}
// 输出:
// main res: a大于10
// app res: undefined
然后我们在把return打开注释:
async function main() {
try {
const res = await fn(11)
console.log('main res:', res);
return res;
} catch (error) {
console.log('main err: ', error);
throw new Error('main err...: ' + error)
}
}
// 输出:
// main res: a大于10
// app res: a大于10
结论:async函数中的return相当于promise函数中的resolve函数,其返回值,可以被下一个流程的async函数的await捕获到。throw Error相当于promise中的reject函数,可以被下一个流程的async函数的catch捕获到。
这里的代码是否能执行到?
不知道你可曾有这样的疑问resolve、reject、throw下边的代码是否可执行,也就是说他们有没有类似return 跳出函数的功能呢?我们再来验证一下:
function fn(a) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (a > 10) {
resolve('a大于10')
console.log('fn resolve next');
} else {
reject('a 不大于 10')
console.log('fn reject next'); // 执行了
}
}, 1000)
})
}
async function main() {
try {
const res = await fn(7)
console.log('main res:', res);
return res;
} catch (error) {
console.log('main err: ', error);
throw new Error('main err...: ' + error)
console.log('throw error next') // 没有执行
}
}
async function app() {
try {
const res = await main();
console.log('app res:', res);
} catch (error) {
console.log('app err:', error)
}
}
app();
/**
输出:
fn reject next
main err: a 不大于 10
app err: Error: main err...: a 不大于 10
at main (/Users/ccc/Documents/Coding/test/async/app.js:23:11)
at process.internalTickCallback (internal/process/next_tick.js:77:7)
*/
上面代码中,第9行reject后边的console.log执行了,第23行throw后边的console.log没有执行。
如果你使用的是vscode,可以看到第24行代码的颜色是不正常的,鼠标移入会显示‘检测到无法访问的代码’,效果如下图:
其实结果你应该已经知道了,为求心安,我们再来验证一下resolve:
function fn(a) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (a > 10) {
resolve('a大于10')
console.log('fn resolve next'); // 执行了
} else {
reject('a 不大于 10')
console.log('fn reject next');
}
}, 1000)
})
}
async function main() {
try {
const res = await fn(11)
console.log('main res:', res);
return res;
} catch (error) {
console.log('main err: ', error);
throw new Error('main err...: ' + error)
console.log('throw error next') // 没有执行
}
}
async function app() {
try {
const res = await main();
console.log('app res:', res);
} catch (error) {
console.log('app err:', error)
}
}
app();
/*
fn resolve next
main res: a大于10
app res: a大于10
*/
好了,求得心安。下结论吧:
结论:resolve,reject函数下边的代码依然会正常执行,throw其后的代码是无法执行的(某种效果上说类似于return)
冯教授[wally]原创,转载请注明出处。