首页 > 解决方案 > 以干净的方式包装承诺

问题描述

编辑:审稿人得出的关于这是重复的结论是错误的,并且源于对实际问题的误解。请参阅帖子底部的编辑以获取摘要和解决方案,以及对此问题的评论,确认这实际上不是重复的。

原始问题:我正在为我们团队的前端处理后端通信的逻辑。所有请求都遵循以下模式:

  1. 接受输入(可变)
  2. 预处理输入(与所有输入一致)
  3. 将输入发送到后端(不同,具有开发人员定义的条件逻辑)
  4. 后处理后端响应(对所有人都一致)
  5. 将响应传递给前端的其余部分

我们最近偶然发现了一些静默失败的调用,经过调查,我们意识到问题是最初编写逻辑的方式(通过承诺)需要一个单独的 .catch() 调用,我们在一些地方错过了它。

在查看这个模块时,我还注意到它积累了很多样板文件,主要是对后端的每个调用都写成:

function performOperation(input) {
  input = preprocess(input); // step 2
  return new Promise((resolve, reject) => {
    if (env.local) {
      resolve(/* logic to pull from local cache */);
    } else {
      thirdPartyFetchCall(input).then((response) => {
        resolve(response);
      }).catch((error) => {
        reject(error);
      });
    }
  }).then((output) => {
    return postprocess(output); // step 4
  }).catch((error) => {
    // this is for catching postprocess errors
    console.error(error);
  });
}

遵循这种模式有几十个调用,我想稍微清理一下,以及使最终的错误转储自动(预处理受益于在同一个线程中,因此它的抛出被自动记录,后处理不是这种情况)。

我的想法是将它包装在一个承诺工厂中,然后开发人员可以如下调用:

function performOperation(input) {
  return factory(input).send((processedInput) => {
    if (env.local) {
      return (/* logic to pull from local cache */);
    } else {
      return thirdPartyFetchCall(processedInput);
    }
  });
}

承诺工厂将负责预处理和后处理调用,以及转储后处理错误。问题是我不确定如何从工厂判断是否thirdPartyFetchCall会导致resolvereject同时保持逻辑独立。我可以在传递给的函数返回时调用.thenand ,但在 的情况下,它将返回一个非承诺值,并说服其他开发人员手动承诺它比记住在末尾添加链不太可能。您如何建议我从工厂安全地处理它,只需测试该对象是否是一个承诺?如果我只是从工厂内部调用它,该子句是否仍会触发以响应引发的错误.catch.sendenv.local.catchresolve.catchthirdPartyFetchCallreject在 Promise 声明中没有显式调用?这是与上述内容一起使用的工厂代码示例:

function factory(input) {
  return new Promise((resolve, reject) => {
    return { send: (request) => {
      resolve(request(preprocess(input)));
    }
  }).then((output) => {
    return postprocess(output);
  }).catch((error) => {
    console.error(error);
  });
}

请注意,在上面的工厂reject中,promise 声明中永远不会显式调用,但我仍然希望catch执行链末尾的 以响应postprocess调用中抛出的错误或函数返回的 promise 中的reject调用。thirdPartyFetchCallrequest

编辑:好的,我现在觉得很愚蠢。整个工厂的想法让我误入歧途。.catch()当我真正的主要问题是,如果在声明中没有明确调用拒绝的承诺,子句是否仍会触发,我陷入了实现细节。答案是肯定的,它会的——我可以通过进一步简化测试并在节点中运行它来进行测试:

function test() { throw 'error'; }
let p = new Promise((resolve, reject) => {
  resolve(test());
}).then((r) => {
  console.log('success');
}).catch((r) => {
  console.log('error');
});

标签: javascriptpromise

解决方案


推荐阅读