Обработка ошибок и асинхронное ожидание

Я хотел бы начать этот пост со следующего вопроса:

Что делает этот фрагмент кода:

async function asyncCall() {
    setLoading(true);
    const response = await getApiRequest();
    setLoading(false);
    return response.data;
}

есть что-то общее с нескончаемым прядильщиком?

В течение обычного рабочего дня я иногда просматриваю чужой код для вдохновения (не совсем). Со временем я натыкаюсь на async-await синтаксис и почти Promise..then синтаксис. Не поймите меня неправильно, я не против async-await синтаксиса. Но когда мы обычно используем синтаксис ожидания, мы часто не уделяем достаточно времени обработке ошибок, которые могут возникнуть. Приведу пример. Когда я спросил своего коллегу: «Что, если обещание не сработает?», он ответил: «Все в порядке, я написал на стороне сервера. Он никогда не должен подводить ». Угадай, что? Через два дня кто-то еще прикоснулся к коду сервера, и мы получили пустой экран на демонстрации с клиентом. Приведу еще один пример. Когда я спросил другого сотрудника: «Почему бы просто не использовать Promise… тогда для этого сценария?» затем он ответил: «Ну… это выглядит лучше вот так».

Итак, ответ на мой вопрос - необработанный отказ от обещания.

Я не против использования async-await, если мы принимаем во внимание, что обещание в какой-то момент не сработает. Есть несколько способов аккуратно обработать эти отказы, и я покажу некоторые из них:

1. Обещаю… тогда… лови

Просто замените await на «старый-добрый» синтаксис, который позволяет вам сразу же обрабатывать отклонения обещаний:

function asyncCall() {
    setLoading(true);
return getApiRequest()
        .then(response => response.data)
        .catch(response => showErrorNotification(response)
        .finally(() => setLoading(false);
}

2. Оберните внутри функции асинхронного обработчика

Это нестандартное решение, которое я нашел весьма полезным. Недавно я узнал о response-query, который в значительной степени поддерживает такое решение и даже усложняет:

function handleAsync(promise) {
    return promise
        .then(data => ({data, error: null}))
        .catch(error => ({data: null, error}))
}
...
function asyncCall() {
    setLoading(true);
    const { data, error } = await handleAsync(getApiRequest());
    setLoading(false);
    if (error !== null) {
        showErrorNotification(error);
    }
    return data
}

3. Попробуй… поймай

Обычно я не работаю с try / catch. Хотя для некоторых это может быть полезно:

async function asyncCall() {
    setLoading(true);
    try {
        const response = await getApiRequest();
    } catch (error) {
        showErrorNotification(error);
    } finally {
        setLoading(false);
    }
}

Вывод

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