0. 前言

一篇纯粹的异步错误处理整理文,以例子为基本进行解释。

node -v
8.4.0

1. async / await

function PromiseRejected() {
  return Promise.reject(new Error("Error in PromiseRejected"));
}

function PromiseError() {
  return new Promise(() => {
    throw new Error("Error in PromiseError");
  });
}

async function PromiseLv1() {
  return await PromiseRejected();
  // return await PromiseError();
}

async function PromiseLv2() {
  return await PromiseLv1();
}

async function main() {
  await PromiseLv2();
}

main().then(_ => _);

注释的部分可以调换直接抛错和使用reject,结果都一样:

(node:25564) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: Error in PromiseRejected
(node:25564) [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.

对上面的例子main部分进行修改:

async function main() {
  try {
    await PromiseLv2();
  } catch (e) {
    console.log(e);
  }
}

错误会得到捕获,并打印出来:

Error: Error in PromiseRejected | PromiseError
    at PromiseRejected (/Prog/Codes/NodeJs/SASDN/async/index.js:2:25)
    at PromiseLv1 (/Prog/Codes/NodeJs/SASDN/async/index.js:10:16)
    at PromiseLv2 (/Prog/Codes/NodeJs/SASDN/async/index.js:15:16)
    at main (/Prog/Codes/NodeJs/SASDN/async/index.js:20:11)
    at Object.<anonymous> (/Prog/Codes/NodeJs/SASDN/async/index.js:26:1)
    at Module._compile (module.js:573:30)
    at Object.Module._extensions..js (module.js:584:10)
    at Module.load (module.js:507:32)
    at tryModuleLoad (module.js:470:12)
    at Function.Module._load (module.js:462:3)

在无捕获的情况下可以下面的方法进行全局处理:

process.on('unhandledRejection', function(reason, p){
  console.log("Possibly Unhandled Rejection at: Promise ", p, " reason: ", reason);
});
process.on('uncaughtException', (err) => {
  fs.writeSync(1, `Caught exception: ${err}\n`);
});

1.2 Promise

function PromiseRejected() {
  return Promise.reject(new Error("Error in PromiseRejected"));
}

function PromiseError() {
  return new Promise(() => {
    throw new Error("Error in PromiseError");
  });
}

function PromiseLv1() {
  let exec = PromiseRejected;
  // let exec = PromiseError;

  return exec();
}

function PromiseLv2() {
  return PromiseLv1();
}

function main() {
  PromiseLv2().then(_ => _);
}

main();

Promise版本也是一样的,未捕获的错误就会直接出错:

(node:45779) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: Error in PromiseRejected
(node:45779) [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.

最后可以使用catch的方法捕获错误:

function main() {
  PromiseLv2().then(_ => _).catch((e) => {
    console.log(`Caught in main: ${e.stack}`);
  });
}

1.3 结论

  • 无论是Promise还是Async/Await,实际操作上在错误捕获及处理这点上没有差别
  • 错误抛出 => 中间经过 => 最终捕获,只要是被抛出来的错误,最后都会在堆栈中层层上传,最后得到捕获,这点不需要再担心了,这部分的行为现在和一般的同步语言没差别
  • 所有的异步逻辑都需要放在try catch或最后进行Promise.catch,进行处理,否则无处理的错误会进到process层面
  • process给的2个事件可以最终捕获到未处理的reject和错误

EOF