Появившиеся в JavaScript новые асинхроные конструкции async/await выглядят проще, чем Promise, и, конечно, значительно читабельнее, чем «callback-джунгли». Но одна вещь беспокоила меня — это использование try-catch. Сначала я подумал, что это не проблема, но, к несчастью, мне пришлось работать с цепочкой вызовов API, в которой каждый вызов API имел свое сообщение об ошибке, которое должно было прологировано. Вскоре я понял, что создаю «try/catch-джунгли», которые ничем не лучше «callback-джунглей».
Давайте рассмотрим этот Promise, который возвращает данные или исключение через 2 секунды в зависимости от параметра rejectPromise:
// api.js
const fetchData = async (duration, rejectPromise) => (
new Promise((resolve, reject) => {
setTimeout(() => {
if (rejectPromise) {
reject({
error: 'Error Encountered',
status: 'error'
})
}
resolve({
version: 1,
hello: 'world',
});
}, duration);
})
);
module.exports = {
fetchData,
};
Типичное использование этой функции будет выглядеть так:
const { fetchData } = require('./api');
const callApi = async () => {
try {
const value = await fetchData(2000, false);
console.info(value);
} catch (error) {
console.error(error);
}
}
callApi();
/*
OUTPUT:
{ version: 1, hello: 'world' } (rejectPromise=false)
{ error: 'Error Encountered', status: 'error' } (rejectPromise=true)
*/
Как вы можете видеть, когда параметр rejectPromise является ложным, Promise возвращает значение {version: 1, hello: 'world'}, а когда оно истинно, он вызывает исключение { error: 'Error Encountered', status: 'error' }.
Это типичная реализация async-await. Теперь мы попытаемся использовать Promise, чтобы сделать этот код более простым. Давайте напишем функцию-обертку, которая упростит нам обработку исключений.
// wrapper.js
const wrapper = promise => (
promise
.then(data => ({ data, error: null }))
.catch(error => ({ error, data: null }))
);
module.exports = wrapper;
Мы можем видеть, что функция-обертка принимает Promise в качестве входного параметра и возвращает ошибку или даные с использовнаием конструкции then().catch(). Итак, давайте изменим исходный код с применением функции-обертки:
const { fetchData } = require('./api');
const wrapper = require('./wrapper');
const callApi = async () => {
const { error, data } = await wrapper(fetchData(2000, false));
if (!error) {
console.info(data);
return;
}
console.error(error);
}
callApi();
/*
OUTPUT:
{ version: 1, hello: 'world' } (rejectPromise=false)
{ error: 'Error Encountered', status: 'error' } (rejectPromise=true)
*/
— получаем тот же результат но более читабельным кодом.
Полезные ссылки.
1. Почему [не] надо использовать async/await
Автор: apapacy