在等待函数中为回调设置async关键字有什么用途?

时间:2017-11-14 10:02:04

标签: javascript typescript promise async-await sequelize.js

我有以下代码:

async createApiCall(apiCalls: IApiCallsTable):Promise<IApiCallsTable> {
  try {
    const instance: any = this.db.getEntities().dbo__api_calls.build(apiCalls);
    instance.isNewRecord = true;
    let result = await this.db.getSequelize().transaction( async (transaction) => {
      return instance.save();
    });
    return Promise.resolve(result.dataValues);
  }
  catch (error) {
    console.log(error);
    let message: ILogMessage = {
      code: ResponseErrorCode.unknownError,
      message: ResponseErrorCode.unknownError.toString(),
      meta: error,
      sourceFunction : 'ApiCallsQueries: createApiCall()'
    };
    log.error(message);
    return Promise.reject(error);
  }
}

我想了解是否有必要对async标记匿名函数,即this.db.getSequelize().transaction( async (transaction) => { ...?代码运行完美,但我似乎无法理解标记回调async的原因,如果内部没有等待它的话?这是推荐的模式和/或最佳实践吗?

PS:关于如何改进此代码的任何进一步建议/建议都非常受欢迎:)

2 个答案:

答案 0 :(得分:4)

Sequelize.transaction()需要一个返回Promise的回调函数。 async将任何函数转换为Promise - 返回函数。  但是,Model.save()已经返回Promise,因此您应该只能使用:

await this.db.getSequelize().transaction((tx) => instance.save());

async指示运行时将函数转换为延续传递样式;也就是说,将其转换为返回Promise的函数,该函数最终以函数的返回值结算。这与您是否在函数体中使用await无关。

Sequelize.transaction()的TypeScript定义将此作为您正在使用的方法的签名:

transaction(autoCallback: (t: Transaction) => PromiseLike<any>): Promise<any>;

在TypeScript中,传递&#34;常规&#34;无效。函数到一个需要返回promise函数的回调参数:

let foo: (() => PromiseLike<string>);

foo = async () => "aaa";            // this compiles
foo = () => Promise.resolve("aaa"); // this does as well
foo = () => "aaa";                  // this does *not*

(你可以在TS游乐场here中看到它。)毕竟,Promise<string>string非常不同!

但是,您的代码对已经返回async的方法使用了Promise<Model>,这意味着您的回调实际上会返回Promise<Promise<Model>>。这似乎不对,您的代码实际上应该让TypeScript抱怨result.dataValues,因为result的类型为Promise<Model>,而不是Model。我猜测是通过从具有以下基本形状的代码开始来实现的:

transaction(async (tx) => {
    let foo = await Foo.find();
    // use foo
    return await foo.save();
});

他们的关键字被恰当地使用,因为它不会通过一个承诺。

答案 1 :(得分:2)

如果您未在函数体内使用await关键字,则无需将任何函数标记为async

此规则的一个例外是,如果您希望该回调的行为类似于Promise,那么您的代码示例中就不会这样做。

let result = await this.db.getSequelize().transaction( async (transaction) => {
  return instance.save();
});

即使instance.save返回Promise,我猜它确实如此 - 你已经完全没有使用async了,因为你已经建立了一个Promise链。