JavaScript:使用Async/AWAIT和THEN/CATCH处理异步错误之间的差异

我只是想先发制人地说,我熟悉异步/等待和在JavaScript中的承诺,所以不需要为此将我链接到一些MDN页面。

我有一个获取用户详细信息并将其显示在UI上的函数。


async function someHttpCall() {
  throw 'someHttpCall error'
}
async function fetchUserDetails() {
  throw 'fetchUserDetails error'
}

function displayUserDetails(userDetails) {
  console.log('userDetails:', userDetails)
}

async function fetchUser() {
  try {
    const user = await someHttpCall()
    try {
      const details = await fetchUserDetails(user)
      returndisplayUserDetails(details)
    } catch (fetchUserDetailsError) {
      console.log('fetching user error', fetchUserDetailsError)
    }
  } catch (someHttpCallError) {
    console.log('networking error:', someHttpCallError)
  }
}

它首先通过someHttpCall进行HTTP调用,如果成功,则转到fetchUserDetails,如果也成功,则我们通过returndisplayUserDetails显示有关UI的详细信息。

如果someHttpCall失败,我们将停止并不进行fetchUserDetails调用。换句话说,我们希望将someHttpCall的错误处理和fetchUserDetails的数据处理分开

我编写的函数包含嵌套的try catch块,如果嵌套变得很深,则不能很好地伸缩,我正尝试使用普通thencatch重写它以提高可读性

这是我的第一次尝试

function fetchUser2() {
  someHttpCall()
    .then(
      (user) => fetchUserDetails(user),
      (someHttpCallError) => {
        console.log('networking error:', someHttpCallError)
      }
    )
    .then(
      (details) => {
        displayUserDetails(details)
      }, //
      (fetchUserDetailsError) => {
        console.log('fetching user error', fetchUserDetailsError)
      }
    )
}
这样做的问题是,第二个then将运行,即displayUserDetails即使someHttpCall失败。为了避免这种情况,我不得不让前面的.catch块抛出

这就是更新版本

function fetchUser2() {
  someHttpCall()
    .then(
      (user) => fetchUserDetails(user),
      (someHttpCallError) => {
        console.log('networking error:', someHttpCallError)
        throw someHttpCallError
      }
    )
    .then(
      (details) => {
        displayUserDetails(details)
      }, //
      (fetchUserDetailsError) => {
        console.log('fetching user error', fetchUserDetailsError)
      }
    )
}

但是,现在第二个接球将作为抛出的结果被调用。因此,当someHttpCall失败时,在我们处理了someHttpCallError错误之后,我们将进入这个块(fetchUserDetailsError) => { console.log('fetching user error', fetchUserDetailsError) },这并不好,因为fetchUserDetails从未被调用过,所以我们不需要处理fetchUserDetailsError(我知道someHttpCallError在这种情况下变成了fetchUserDetailsError)

我可以在其中添加一些条件检查来区分这两个错误,但这似乎不太理想。因此,我想知道如何通过使用.then.catch在这里实现相同的目标来改进这一点。


解决方案

我想知道如何通过使用.then.catch来改进这一点,以在这里实现相同的目标

如果您想要复制相同的行为,则无法避免嵌套:

function fetchUser2() {
  return someHttpCall().then(
    (user) => {
      return fetchUserDetails(user).then(
        (details) => {
          return displayUserDetails(details)
        },
        (fetchUserDetailsError) => {
          console.log('fetching user error', fetchUserDetailsError)
        }
      )
    },
    (someHttpCallError) => {
      console.log('networking error:', someHttpCallError)
      throw someHttpCallError
    }
  )
}

(完全等同于try/catch将使用.then(…).catch(…) instead of .then(…, …),但you might not actually want that。)

我编写的函数是[嵌套的],如果嵌套变得很深,它就不能很好地伸缩,而我正试图重写它以提高可读性[…]

为此,我建议将await.catch()结合使用:

async function fetchUser() {
  try {
    const user = await someHttpCall().catch(someHttpCallError => {
      throw new Error('networking error', {cause: someHttpCallError});
    });
    const details = await fetchUserDetails(user).catch(fetchUserDetailsError => {
      throw new Error('fetching user error', {cause: fetchUserDetailsError});
    });
    return displayUserDetails(details);
  } catch (someError) {
    console.log(someError.message, someError.cause);
  }
}

(Errorcause选项仍然很新,您可能需要一个填充)

相关文章