Мне было интересно, следует ли мне использовать несколько try catch внутри асинхронных функций для правильной обработки различных ошибок, которые могут возникнуть во время асинхронных вызовов, или я могу использовать только одну?

const exec = async (id: string) => {
  let user: User;
  try {
    user = await fetchUserData(id) 
  } catch(e) {
    reportError(e.message)
    return null;
  }
  let posts: Post[]
  try {
    posts = await fetchPosts(user.preferences)
  } catch (e) {
    return [];
  }
}

Метод «поймай и брось»

И позже я понял, что я могу поймать ошибку прямо на месте и повторно выдать общую ошибку, которая будет обработана try catch

const getRecommendedPosts = async (id: string) => {
  try {
    const user = await fetchUser(id).catch((e) => {
      if(e.code === 404) throw new Error('User not found')
      if(e.code === 403) throw new Error('You are not allowed to view this user posts')
      throw new Error('Failed to load user data')
    })
    const posts = await fetchPosts(user.preferences).catch((e) => {
      if(e.status === 500) throw new Error('API Failed to load posts, try again later')
      return []
    })
    return posts;
  } catch(e) {
    reportError(e.message);
    return null;
  }
}

В этом сценарии мы можем обрабатывать различные сбои и либо возвращать пустой список сообщений, если API не удалось загрузить сообщения, либо отображать сообщение об ошибке для пользователя.

Следуя коду, если нам удастся загрузить пользовательские настройки, мы сможем загрузить рекомендуемые сообщения и вернуть их.

Но в случае сбоя загрузки пользовательских данных мы правильно обрабатываем это с помощью соответствующего сообщения или другой логики (если мы используем разные классы для ошибок, как показано ниже).

В случае, если нам не удалось загрузить сообщения, мы можем вернуть пустой массив, возвращаемый ошибкой .catch или retrhow обработанной ошибкой.

Подклассы ошибок

Для обработки различных ошибок в одной попытке перехвата, которые требуют дополнительной логики, мы можем использовать подклассы, такие как:

class UserFetchError extends Error {
  constructor(message, public userId) {
    super(message);
  }
}

const getRecommendedPosts = async (id: string) => {
  try {
    const user = await fetchUser(id).catch((e) => {
      throw new UserFetchError('User not found', id)
    })
    const posts = await fetchPosts(user.preferences).catch((e) => {
      throw new Error('API Failed to load posts, try again later')
    })
  } catch(e) {
    if(e instanceof UserFetchError) {
      reportError(e.message, e.userId);
    } else {
      showMessage(e.message)
    }
    return null;
  }
}