NodeJS - 正确捕获异步函数的错误

NodeJS - Properly catch errors of async functions

我正在编写一个脚本,通过 API 从 Google 云指标中提取数据,这时我无意中发现我不知道如何正确捕获异步函数的错误。 :O

这是来自 google 云的示例代码:

// Imports the Google Cloud client library
const monitoring = require('@google-cloud/monitoring');

// Creates a client
const client = new monitoring.MetricServiceClient();

/**
 * TODO(developer): Uncomment and edit the following lines of code.
 */
const projectId = 'XXXXXXXXX';

async function getMetrics() {

  const request = {
    name: client.projectPath(projectId),
    filter: 'metric.type="cloudsql.googleapis.com/database/cpu/utilization"',
    interval: {
      startTime: {
        // Limit results to the last 20 minutes
        seconds: Date.now() / 1000 - 60 * 1,
      },
      endTime: {
        seconds: Date.now() / 1000,
      },
    },
    // Don't return time series data, instead just return information about
    // the metrics that match the filter
    view: 'HEADERS',
  };

  // Writes time series data
  console.log('start')
  const [timeSeries] = await client.listTimeSeries(request);
  console.log('Found data points for the following instances:');
  timeSeries.forEach(data => {
    console.log(data.metric.labels.instance_name);
  });
}


getMetrics();

函数listTimeSeriesreturns一个承诺。我收到一条错误消息,提示我需要经过身份验证才能执行该操作,没问题。

问题是我无法捕获该错误。
我尝试用 try {...} catch (err) {...} 块围绕调用,但没有被捕获。
我试着像这样抓住它 const [timeSeries] = await client.listTimeSeries(request).catch(console.log); - 运气不好。

我一定是遗漏了什么,因为我是 nodeJS 的新手,不支持从异步函数捕获错误。

我正在使用 nodeJS v14。

我想念什么?
提前致谢!


编辑

按照@CherryDT 的要求,这里是完整的错误输出:

希望不要太模糊。


编辑

事实证明,我一直试图捕捉错误的方式是好的。
问题的发生是因为 listTimeSeries 函数(来自外部库)引发了一个错误而不是拒绝承诺,这是不可能捕捉到的。

谢谢大家。

你可以做到。

(async function() {
    try {
      await getMetrics();
    } catch(error) {
      console.log("Error occured:", error);
    }
})();

请注意,如果您试图捕获 Promise 中的错误,您可以使用 .then(() => { }).catch(err => { }) 样式,但对于 async/await 您将需要 try { } catch(err) { } 样式来捕获错误。

编辑

通过这样做,如果承诺被拒绝,它必须捕获任何错误。如果您仍然无法捕捉到错误,这意味着您正在使用的库没有正确 reject 承诺 (Promise.reject()),而是在承诺中进行了硬编码 throw error而不是拒绝一个。对于这种情况,您不能对错误捕获做任何事情。

请注意,我指的是“异步函数”和“异步函数”。在 Javascript 中,“异步函数”表示 function created with the async keyword,而当我说“异步函数”时,我指的是传统意义上的任何异步运行的函数。在 Javascript 中,使用 async 关键字创建的函数实际上只是底层的承诺。

如果异步函数(在 promises 内)抛出的错误可以被捕获,您的代码 工作。不幸的是,they can't. Unless the function is using the async function syntax, errors in promises must be wrapped with reject. See the MDN example 我们在这里看到的陷阱:

// Throwing an error will call the catch method most of the time
var p1 = new Promise(function(resolve, reject) {
  throw new Error('Uh-oh!');
});

p1.catch(function(e) {
  console.error(e); // "Uh-oh!"
});

// Errors thrown inside asynchronous functions will act like uncaught errors
var p2 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    throw new Error('Uncaught Exception!');
  }, 1000);
});

p2.catch(function(e) {
  console.error(e); // This is never called
});

// Errors thrown after resolve is called will be silenced
var p3 = new Promise(function(resolve, reject) {
  resolve();
  throw new Error('Silenced Exception!');
});

p3.catch(function(e) {
   console.error(e); // This is never called
});

我相信 this is the code 在下面的库中抛出错误。请注意,另一个错误正在被正确 rejected。所有评论都是我的。

for (const methodName of metricServiceStubMethods) {
  const callPromise = this.metricServiceStub.then(
    stub => (...args: Array<{}>) => {
      if (this._terminated) {
        // This is the right thing to do!
        return Promise.reject('The client has already been closed.');
      }
      const func = stub[methodName];
      return func.apply(stub, args);
    },
    (err: Error | null | undefined) => () => {
      // If this was an async function (as in, using the keyword async,
      // not just literally an asynchronous function), this would work,
      // because the async keyword is just syntactic sugar for creating
      // a promise. But it's not so it can't be caught!
      throw err;
    }
  );

我相信,在这种情况下,不幸的是您无法捕获此错误。