promise reject处理

  1. function fn(a) {
  2. return new Promise((resolve, reject) => {
  3. setTimeout(() => {
  4. if (a > 10) {
  5. resolve('a大于10')
  6. } else {
  7. reject('a 不大于 10')
  8. }
  9. }, 1000)
  10. })
  11. }
  12. fn(7)
  13. .then(res => {
  14. console.log('resolve', res);
  15. }, err => {
  16. console.log('reject', err)
  17. })
  18. .catch(err => {
  19. console.log('err:', err);
  20. })
  21. // 输出:reject a 不大于 10

上述代码中fn返回一个promise,因为7<10 所以promise 走的是reject分支。
promise的then方法接收两个参数:

  • 第一个是resolve函数,参数是promise抛出resolve时的参数
  • 第二个参数是reject函数,参数是promise抛出reject时的参数

这里的输出结果是 reject a 不大于 10 ,也就是说这里走了reject回调函数,没有走catch函数。

再来看第二种情况:

  1. fn(7)
  2. .then(res => {
  3. console.log('resolve', res);
  4. })
  5. .catch(err => {
  6. console.log('err:', err);
  7. })
  8. // 输出:err: a 不大于 10

这里我们把then函数的第二个参数(reject函数)去掉,执行结果是:err: a 不大于 10 。也就是说走了catch函数,catch捕获了reject的返回内容

结论:

  1. catch可以捕获reject的内容
  2. then函数的第二个参数(reject回调函数)与catch同时存在时,reject优先捕获,catch失效
  3. 建议使用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行代码的颜色是不正常的,鼠标移入会显示‘检测到无法访问的代码’,效果如下图:
image.png

其实结果你应该已经知道了,为求心安,我们再来验证一下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]原创,转载请注明出处。