【问题标题】:Using async/await and try/catch to make tiered api calls使用 async/await 和 try/catch 进行分层 api 调用
【发布时间】:2018-03-29 19:50:27
【问题描述】:

朋友们!

我需要调用一个 api;如果失败,我需要使用不同的参数调用相同的 api;如果再次失败,我需要使用第三个不同的参数调用相同的 api;如果在那之后它最终失败了,那就是一个实际的错误,并且可以解决。

我能想到的唯一方法是使用嵌套的 try/catch 语句,ala:

const identityCheck = async (slug) => {
  let res;
  try {
    res = await Bundle.sdk.find(slug);
  } catch (err) {
    console.log('Fragment didn\'t work ========', slug, err);

    try {
      res = await Bundle.sdk.find(`package/${slug}`);
    } catch (e) {
      console.log('Fragment didn\'t work package ========', e);

      try {
        res = await Bundle.sdk.find(`${slug}-list`);
      } catch (error) {
        console.log('None of the fragments worked================.', error);
      }
    }
  }

  return logResponse(res);
};

identityCheck('fashion');

但似乎必须有另一种更简单的方法来做到这一点。我尝试归结为一个重试函数,但这最终会导致更多的代码和不太清晰的方式:

const identityCheck = (slug) => {
  const toTry = [
    slug,
    `package/${slug}`,
    `${slug}-list`
  ];

  return new Promise((resolve, reject) => {
    let res;
    let tryValIndex = 0;

    const attempt = async () => {
      try {
        res = await Bundle.sdk.find(toTry[tryValIndex]);
        return resolve(logResponse(res));
      } catch (err) {
        console.log(`toTry ${toTry[tryValIndex]} did not work ========`, slug, err);

        if (tryValIndex >= toTry.length) {
          return reject(new Error('Everything is broken forever.'));
        }

        tryValIndex++;
        attempt();
      }
    };

    attempt();
  });
};

感谢您的指导和意见!

【问题讨论】:

    标签: javascript async-await try-catch es6-promise


    【解决方案1】:

    避免使用Promise constructor antipattern,并使用参数而不是外部范围变量来进行递归计数:

    function identityCheck(slug) {
      const toTry = [
        slug,
        `package/${slug}`,
        `${slug}-list`
      ];
      async function attempt(tryIndex) {
        try {
          return await Bundle.sdk.find(toTry[tryIndex]);
        } catch (err) {
          console.log(`toTry ${toTry[tryIndex]} did not work ========`, slug, err);
          if (tryIndex >= toTry.length) {
            throw new Error('Everything is broken forever.'));
          } else {
            return attempt(tryIndex+1);
          }
        }
      }
      return attempt(0);
    }
    

    【讨论】:

    • 哦,注意了!这是否意味着您认为这个版本比嵌套的 try/catch 或只是一般有用的 intel 更好?
    • 是的,它可以更好:使用更多 toTry 值进行扩展更容易(只需将它们添加到数组中),如果代码中的其他位置进一步抽象出来可能会很有用需要类似的重试逻辑。如果这些原因都不重要,那就归结为对简单与抽象的偏好。
    • 可爱,感谢您的快速反馈!可能会等待一些额外的玩笑,然后会接受答案。 :)
    • 应该在catch() 中使用console.error() 而不是console.log()
    • @guest271314 不,为什么会这样?
    【解决方案2】:

    按照 Bergi 的回答,但试图保留原始结构以避免“更多代码”:

    const idCheck = async (slug, alsoTry = [`package/${slug}`, `${slug}-list`]) => {
      let res;
      try {
        res = await Bundle.sdk.find(slug);
      } catch (err) {
        if (!alsoTry.length) throw err;
        return idCheck(alsoTry.shift(), alsoTry);
      }
      return logResponse(res);
    };
    
    idCheck('fashion');
    

    这利用了非常强大的默认参数。

    同样的复杂性,但在美学上更接近嵌套的 try-blocks,也许是一种更简单的模式。

    【讨论】:

      猜你喜欢
      • 2019-03-14
      • 2021-08-28
      • 2017-11-23
      • 2018-07-05
      • 2019-09-30
      • 2020-02-20
      相关资源
      最近更新 更多