代码有效,但是在承诺中使用 try/catch 块是最佳实践吗?

Code works, but is it best practice to have a try/catch block inside a promise?

Promise 包裹 try/catch 是好习惯吗?我正在查看下面的代码,我似乎无法理解 Promise 中有一个 try/catch 块的必要性。另外,为什么没有 Promise 拒绝的地方,正如您在 catch 块中看到的那样,Promise 解析。请帮助我理解这段代码,就最佳实践和效率而言,在 Promise.

中包含 try/catch 的要点

我也非常感谢有关清理冗余代码的任何建议。

getRoute(): any {
    return async (request: any, reply: any) => {
      const result = new Promise<string>( async (resolve, reject) => {
        try {
          let userIsValid = await this.validator.validate(request.payload, RegisterUserValidator);
          if (userIsValid.error) {
            resolve(responseHelper.getErrorResponse(ResponseErrorCode.joiValidatorError, userIsValid.error));
            throw new ControlFlowNonError();
          }
          let results = await this.authUser.registerUser(request.payload);
          resolve(responseHelper.getSuccessResponse(results, null));
        }
        catch (error) {
          let message: ILogMessage = {
            code: ResponseErrorCode.unknownError,
            message: ResponseErrorCode.unknownError.toString(),
            meta: error,
            sourceFunction : 'ApiDataCreateCredentials: getRoute()'
          };
          this.logHelper.error(message);
          resolve(error);
        }
      });
      reply(result);
    };
  };

Is it best practice to have a try/catch block inside a promise [executor function]?

不,这不是最佳做法。几乎没有理由在 promise 执行器函数中使用 promises。因为当你这样做时,你根本不需要外部的、手动创建的承诺。你可以 return 内心的承诺。那就是 Promise constructor anti-pattern.

仅供参考,虽然这不是你的情况,但使用 try/catch 处理 promise 执行器中的常规异常是合理的(如果首先实际需要手动创建的 promise 执行器,并且如果经常出现的异常令人担忧,您想在本地处理它们。


这是关于如何实现相同逻辑的另一个想法。这消除了 promise anti-pattern 用另一个手动创建的承诺包围一个承诺,并使用承诺流控制使 userIsValid.error 转到日志错误代码。我没有看到在这里使用 await 有什么特别的优势,所以我切换回只使用 .then().catch()。我不了解 TypeScript,所以这是代码的常规 Javascript 版本,但您大概可以自己添加细微的语法差异以将其转回 TypeScript:

getRoute(): function() {
    return function(request, reply) {
        return this.validator.validate(request.payload, RegisterUserValidator).then(userIsValid => {
            if (userIsValid.error) {
                // treat this as an error condition
                throw responseHelper.getErrorResponse(ResponseErrorCode.joiValidatorError, userIsValid.error);
            }
            return this.authUser.registerUser(request.payload).then(results => responseHelper.getSuccessResponse(results, null));
        }).catch(error => {
          let message: ILogMessage = {
            code: ResponseErrorCode.unknownError,
            message: ResponseErrorCode.unknownError.toString(),
            meta: error,
            sourceFunction : 'ApiDataCreateCredentials: getRoute()'
          };
          this.logHelper.error(message);
          // turn back into resolved promise with error as the result
          return error;
        }).then(reply);        // always call reply
    }
}    

您的实施似乎不太理想的地方:

  1. Promise anti-pattern(创建一个不必要的包装承诺)。
  2. 多次调用resolve()(第二个将被忽略,但这样编码似乎不太理想)
  3. 这里使用 async/await 似乎没有什么特别的好处。这似乎使流程复杂化(在我看来)。
  4. resolve() 后跟 throw 是阅读代码时真正令人头疼的问题。是的,人们最终可以弄清楚您要做什么,但这是一种奇怪的方法。我的方案更具语义性。 if (userIsValid.error) 对您来说实际上只是一个错误条件,因此以这种方式编码只会使它更加明显。然后,由于您希望所有错误都像没有错误一样继续进行(在记录之后),我们只需正常地使 .catch() 处理程序 return 允许最后一个 .then() 处理程序始终被调用.

与您的主题相关的其他参考资料: