Перепишите «callback hell» JavaScript‑примеры с вложенными колбэками в более читаемую форму, используя промисы и async/await; обсудите влияние на обработку ошибок и управление ресурсами

26 Мая в 10:03
12 +1
0
Ответы
1
Ниже — короткие примеры «callback hell» и их преобразование в Promises и в async/await, затем краткое обсуждение влияния на обработку ошибок и управление ресурсами.
1) Пример: чтение файла, парсинг JSON, запись результата
Callback‑версия (плохо читаема):
```js
const fs = require('fs');
fs.readFile('in.json', 'utf8', (err, data) => {
if (err) return console.error(err);
let obj;
try {
obj = JSON.parse(data);
} catch (e) {
return console.error(e);
}
obj.processed = true;
fs.writeFile('out.json', JSON.stringify(obj), (err) => {
if (err) return console.error(err);
console.log('done');
});
});
```
Promise‑версия (с явным промисификацией или использованием fs.promises):
```js
const fs = require('fs').promises;
fs.readFile('in.json', 'utf8')
.then(data => {
const obj = JSON.parse(data);
obj.processed = true;
return fs.writeFile('out.json', JSON.stringify(obj));
})
.then(() => console.log('done'))
.catch(err => console.error(err));
```
Async/await (самая читаемая для последовательных шагов):
```js
const fs = require('fs').promises;
async function processFile() {
try {
const data = await fs.readFile('in.json', 'utf8');
const obj = JSON.parse(data);
obj.processed = true;
await fs.writeFile('out.json', JSON.stringify(obj));
console.log('done');
} catch (err) {
console.error(err);
}
}
processFile();
```
2) Пример: последовательные асинхронные запросы (получить пользователя → получить заказы → отправить уведомление)
Callback‑ад:
```js
getUser(id, (err, user) => {
if (err) return cb(err);
getOrders(user.id, (err, orders) => {
if (err) return cb(err);
sendNotification(user.email, orders, (err) => {
if (err) return cb(err);
cb(null, 'ok');
});
});
});
```
Promise‑цепочка:
```js
getUserAsync(id)
.then(user => getOrdersAsync(user.id).then(orders => ({ user, orders })))
.then(({ user, orders }) => sendNotificationAsync(user.email, orders))
.then(() => 'ok')
.catch(err => { throw err; });
```
Async/await (понятно и линейно):
```js
async function handle(id) {
try {
const user = await getUserAsync(id);
const orders = await getOrdersAsync(user.id);
await sendNotificationAsync(user.email, orders);
return 'ok';
} catch (err) {
throw err; // или обработать здесь
}
}
```
Параллелизация (если независимы): использовать Promise.all
```js
// получить детали нескольких ресурсов параллельно
const [a, b] = await Promise.all([fetchA(), fetchB()]);
```
3) Ресурсы и транзакции — гарантированное освобождение
Callback‑стиль сложно корректно закрыть ресурсы на всех ветках ошибок. С async/await используем try/finally:
```js
async function withTransaction(db, fn) {
const tx = await db.beginTransaction();
try {
const result = await fn(tx);
await tx.commit();
return result;
} catch (err) {
await tx.rollback();
throw err;
} finally {
await tx.release(); // важно гарантированно вызвать
}
}
```
Обсуждение влияния на обработку ошибок и управление ресурсами (кратко):
- Читаемость и структура:
- Callbacks: быстро растёт вложенность, дублирование проверок ошибок.
- Promises/async: линейный код, проще читать и тестировать.
- Обработка ошибок:
- Callbacks: надо вручную проверять `err` в каждом колбэке; легко забыть.
- Promises: исключения и reject автоматом всплывают по цепочке; используем `.catch`.
- Async/await: привычный try/catch; исключение пробрасывается как в синхронном коде.
- Важно: необработанные rejection дают warning/ошибку в рантайме — всегда обрабатывать `.catch` или try/catch.
- Управление ресурсами (файлы, соединения, транзакции):
- С async/await легче гарантировать cleanup через `try/finally` (закрыть сокет/файл/сессию в `finally`).
- Для параллельных задач использовать `Promise.allSettled` или ловить ошибки индивидуально, чтобы не потерять закрытие ресурсов.
- Для отмены операций — AbortController/AbortSignal (fetch, некоторые библиотеки) для корректного прерывания и освобождения.
- Конкуренция и производительность:
- await последовательно ждёт; для независимых задач применяйте `Promise.all` для параллелизации.
- Следите за лимитами (создание сотен параллельных соединений может перегрузить систему) — используйте пул/лимитирование.
- Отладка и стек‑трейсы:
- Promises/async дают более понятные стек‑трейсы по сравнению с глубокой вложенностью колбэков, но всё ещё стоит обрабатывать/логировать ошибки рядом с местом возникновения.
Вывод: перевод кода из callback‑вложений в Promises/async‑await делает код чище, упрощает обработку ошибок и даёт удобные паттерны для гарантированного освобождения ресурсов (try/finally, транзакции, AbortController).
26 Мая в 10:10
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир