【问题标题】:Combine two service calls and return the values合并两个服务调用并返回值
【发布时间】:2020-02-16 05:38:15
【问题描述】:

你好,我想合并 2 个电话。并返回它。但是如果两个都失败了,我应该抓住它,如果两个调用中的任何一个失败,那没关系,我可以返回一个有效的。

这是我尝试过的。

我在两个电话中都有问题。如何将其移至 promise.all?

router.get('/services', (req, res) => {

    let arr = [];

    const call1 = service1()
        .then(res => arr.push({ res, type: 'service1'} ))
        .catch(error => res.status(error.status).json(error));

    const call2 = service2()
        .then(res => arr.push({ res, type: 'service2'} ))
        .catch(error => res.status(error.status).json(error));
})

Promise.all([service1, service2]).then(values => { 
  // not sure what to do here
});

节点版本:v8.11.1

【问题讨论】:

  • 您使用的是哪个版本的Node
  • 您还有问题吗?

标签: javascript


【解决方案1】:

在服务调用上调用.catch会确保在Promise.all()中传递给.then的回调始终会被调用,因此需要您自己处理错误:

async function callService(fn, type) {
  return service1().then(res => ({ res, type })).catch(err => ({ err }));
}

router.get('/services', (req, res) => {
  const calls = [callService(service1, 'service1'), callService(service2, 'service2')];
  return Promise.all(calls).then(arr => {
    if (arr.every(call => call.err)) {
      // Both elements in arr are errors, handle here
      return;
    }

    // At least 1 was not an error, handle here
  });

【讨论】:

  • 当你的 Promise 抛出错误时,使用 .catch 的返回值而不是 .then 的返回值。这允许承诺继续被链接 - 否则,您的 Promise.all 将不得不处理错误。
【解决方案2】:

如果Promise 失败,Promise.all 将很遗憾地返回错误,因此它不会按照您想要的方式工作。

假设您使用的是Node.js8 或以上,您可以使用async/await 进行两次异步调用,并检查其中一个是否返回错误:

router.get(`/services`, (req, res) => {
  // this is just a simple check, but gives you an idea
  const isError = (arg) => {
    return arg instanceof Error
  }

  async function processRequest() {
    const arr = []

    const call1 = await service1().catch(error => error)
    const call2 = await service2().catch(error => error)

    if (!isError(call1)) {
      arr.push({ res: call1, type: `service1` })
    }
    if (!isError(call2)) {
      arr.push({ res: call2, type: `service2` })
    }
    if (isError(cal1) && isError(cal2)) {
      res.status(call1.status).json(call1)
      return
    }
    res.status(200).json(arr)
  }
  processRequest()
})

或者,如果您使用的是Node12.10 或更高版本,您可以使用Promise.allSettled,这将完全满足您的需求。

Promise.allSettled() 方法返回一个在所有给定的 Promise 都已解决或被拒绝后解决的 Promise,并带有一个对象数组,每个对象描述每个 Promise 的结果。

在您的情况下应用它,它将如下所示:

router.get(`/services`, (req, res) => {
  Promise.allSettled([
    service1(),
    service2()
  ])
  .then(results => {
    const arr = results
      .filter(result => result.status === `fulfilled`)
      .map(result => result.value)

    if (arr.length === 0) {
      const { reason } = results.find(result => result.status === `rejected`)
      res.status(reason.status).json(reason)
      return
    }
    res.status(200).json(arr)
  })
  .catch(error => {
    // handle other errors appropriately
    res.status(500).json(...)
  })
})

【讨论】:

  • 您在解释中提到了async/await,但在调用service1service2 时未能使用它。应该改为:const call1 = await service1().catch(error => error)
猜你喜欢
  • 1970-01-01
  • 2012-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-08
  • 2012-04-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多