【问题标题】:Async/Await error handling异步/等待错误处理
【发布时间】:2018-07-29 07:21:43
【问题描述】:

我正在尝试处理我的 async 方法引发的自定义错误,但 try catch 块无法正常工作。

我认为我这样做的方式应该可以工作,但错误没有被捕获,程序通过在终端中显示而终止。

这里是它抛出错误的地方:

async setupTap(tap) {
  const model = this.connection.model('Tap', TapSchema);

  await model.findOneAndUpdate({ id: tap.id }, tap, (err, result) => {
    let error = null;
    if (!result) {
      throw new Error('Tap doesn\'t exists', 404);
    }
    return result;
  });
}

然后,错误处理代码:

async setupTapHandler(request, h) {
  const tapData = {
    id: request.params.id,
    clientId: request.payload.clientId,
    beerId: request.payload.beerId,
    kegId: request.payload.kegId,
  };

  try {
    await this.kegeratorApi.setupTap(tapData);
  } catch (e) {
    if (e.code === 404) return h.response().code(404);
  }

  return h.response().code(204);
}

有人可以帮助我吗?

我还看了其他话题:

Correct Try...Catch Syntax Using Async/Await

How to properly implement error handling in async/await case

【问题讨论】:

  • 是什么让你认为new Error("string", 404) 会导致e.code == 404
  • 你是怎么调用这个函数的?
  • 注意,你在findOneAndUpdate 的回调中抛出(并返回) - 所以,这无论如何都不会按预期工作
  • 只要参考@JaromandaX 的 cmets,您就有了解决方案。

标签: javascript node.js error-handling promise async-await


【解决方案1】:

函数 findOneAndUpdate 返回一个promise,因此不需要回调。如果需要回调并且您无法更新到较新的版本,那么可能是wrap calls in a promise(在To use a callback api as promise you can do: 下)

然后你想设置错误的代码,你不能用构造函数来做。

async setupTap(tap) {
  const model = this.connection.model('Tap', TapSchema);

  const result =   await model.findOneAndUpdate({ id: tap.id }, tap);
  if (!result) {
    const e = new Error('Tap doesn\'t exists');
    e.code = 404;
    throw(e);
  }
  return result;
}

async setupTapHandler(request, h) {
  const tapData = {
    id: request.params.id,
    clientId: request.payload.clientId,
    beerId: request.payload.beerId,
    kegId: request.payload.kegId,
  };

  try {
    await this.kegeratorApi.setupTap(tapData);
  } catch (e) {
    if (e.code === 404) return h.response().code(404);
  }

  return h.response().code(204);
}

【讨论】:

  • 想太多了。如果测试只是“结果”是否为空/假,并且 only 的结果是发送 404,那么所有代码​​都是多余的。检查我的答案,你会得到同样的结果,但要简单得多。
  • findOneAndUpdate() 不返回查询,而不是承诺?
  • @jfriend00 不确定,这就是为什么我添加了将回调包装为承诺的链接,但this documentation 没有提到.exec 作为承诺开始,旧版本或其他库可能需要它,如果库版本足够旧,那么它可能只是回调。
  • 好的,我想这取决于 OP 使用的 DB 版本。我在这里查看猫鼬文档:mongoosejs.com/docs/api.html。在任何一种情况下,OP 都必须停止使用回调并使用await 的承诺接口来完成它的工作。
【解决方案2】:

如果您正在等待一个 Promise,您只能使用 await 成功等待异步操作。假设您使用的是猫鼬,我不太了解猫鼬,但如果您将回调传递给model.findOneAndUpdate(),它似乎不会返回承诺。相反,它会执行并将结果放入回调中。

此外,从这样的回调中执行throw 只会将数据扔到数据库中(调用回调的代码),对您没有任何好处。要让 throw 做出拒绝的承诺,您需要从异步函数的顶层抛出,或者从 .then().catch() 处理程序或承诺执行器函数内抛出。这就是 throw 导致 promise 被拒绝的地方。

这里的关键是您要对数据库使用 Promise 接口,而不是回调接口。如果你不传递回调,那么它会返回一个查询,你可以使用.exec() 来获得一个promise,然后你可以使用await

此外,您没有构建一个将 .code 属性设置为 404 的错误对象。这不是错误对象构造函数支持的属性,因此如果您想要该属性,您有手动设置。

我建议这样做:

async setupTap(tap) {
    const model = this.connection.model('Tap', TapSchema);

    let result = await model.findOneAndUpdate({ id: tap.id }, tap).exec();
    if (!result) {
        let err = new Error('Tap doesn\'t exists');
        err.code = 404;
        throw err;
    }
    return result;
}

或者,这里只有一个异步操作,使用await 并没有太多好处。你可以这样做:

setupTap(tap) {
    const model = this.connection.model('Tap', TapSchema);

    return model.findOneAndUpdate({ id: tap.id }, tap).exec().then(result => {
        if (!result) {
            let err = new Error('Tap doesn\'t exists');
            err.code = 404;
            throw err;
        }
        return result;
    });
}

【讨论】:

    猜你喜欢
    • 2022-01-09
    • 2018-04-06
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    • 2018-11-12
    • 1970-01-01
    • 2022-01-02
    • 2020-06-29
    相关资源
    最近更新 更多