Добавить в корзинуПозвонить
Найти в Дзене
Prizrak Developer

Асинхронщина в Node.js: От колбэков к async/await

Вступление Node.js — крут во многом благодаря своей способности не тормозить выполнение, работая с задачами асинхронно. Но как разобраться с этой асинхронностью? Если в примере с сервером мы обошлись простым колбэком, то в реальной жизни обычно хочется чего-то помощнее. Щас посмотрим, как развивался асинхронный код: от колбэчного ада до классных промисов и удобного async/await. Проблема ад колбэков: // Классическая проблема вложенных колбэков readFile('file1.txt', (err, data1) => { if (err) throw err; readFile('file2.txt', (err, data2) => { if (err) throw err; writeFile('result.txt', data1 + data2, (err) => { if (err) throw err; console.log('Готово!'); }); }); }); Решение 1: Промисы (Promises) Промисы – это штуки, которые показывают, чем закончилась асинхронная операция (успехом или провалом). Что важно знать: Состояния: pending (в процессе), fulfilled (готово), rejected (отклонено) Методы: .then() – для обработки успехов, .catch() – для ловли ошибок Цепочки: позволяют выполнять асинхр
Оглавление

Вступление

Node.js — крут во многом благодаря своей способности не тормозить выполнение, работая с задачами асинхронно. Но как разобраться с этой асинхронностью? Если в примере с сервером мы обошлись простым колбэком, то в реальной жизни обычно хочется чего-то помощнее. Щас посмотрим, как развивался асинхронный код: от колбэчного ада до классных промисов и удобного async/await.

Проблема ад колбэков:

// Классическая проблема вложенных колбэков readFile('file1.txt', (err, data1) => { if (err) throw err; readFile('file2.txt', (err, data2) => { if (err) throw err; writeFile('result.txt', data1 + data2, (err) => { if (err) throw err; console.log('Готово!'); }); }); });

Решение 1: Промисы (Promises)

Промисы – это штуки, которые показывают, чем закончилась асинхронная операция (успехом или провалом).

Что важно знать:

Состояния: pending (в процессе), fulfilled (готово), rejected (отклонено)

Методы: .then() – для обработки успехов, .catch() – для ловли ошибок

Цепочки: позволяют выполнять асинхронные штуки по очереди

Пример: Читаем файл с помощью промисов.

// Предположим, что readFilePromise возвращает промис const fs = require('fs').promises; fs.readFile('config.json', 'utf8') .then(data => { console.log('Файл прочитан успешно'); const config = JSON.parse(data); return config; // Передаем в следующий then }) .then(config => { console.log('Имя приложения:', config.appName); return fs.writeFile('output.log', `Конфиг загружен: ${new Date()}`); }) .then(() => { console.log('Лог записан'); }) .catch(error => { console.error('Произошла ошибка:', error.message); });

Решение 2: Async/Await — современный подход

Синтаксис async/await делает асинхронный код похожим на синхронный, что упрощает его чтение и поддержку.

Ключевые моменты:

  • async функция всегда возвращает промис
  • await можно использовать только внутри async функций
  • Код выполняется «сверху вниз», что интуитивно понятнее

Пример: Практическое использование async/await

const fs = require('fs').promises; const axios = require('axios'); // популярная библиотека для HTTP-запросов async function fetchUserData(userId) { try { // 1. Читаем локальный файл с настройками const settings = await fs.readFile('settings.json', 'utf8'); const { apiUrl } = JSON.parse(settings); // 2. Делаем HTTP-запрос к API console.log('Загружаем данные пользователя...'); const response = await axios.get(`${apiUrl}/users/${userId}`); // 3. Обрабатываем полученные данные const user = response.data; user.lastAccess = new Date(); // 4. Сохраняем обновленные данные await fs.writeFile( `user-${userId}.json`, JSON.stringify(user, null, 2) ); console.log(`Данные пользователя ${user.name} сохранены!`); return user; } catch (error) { console.error('Ошибка в процессе загрузки:', error.message); // Можно вернуть значение по умолчанию или пробросить ошибку дальше throw error; } } // Использование функции async function main() { try { const user = await fetchUserData(123); console.log('Работа завершена успешно'); } catch (error) { console.log('Не удалось выполнить операцию'); } } main();

Полезные паттерны

Параллельное выполнение:

async function loadMultipleResources() { // Запускаем все промисы параллельно const [users, posts, settings] = await Promise.all([ fetch('/api/users'), fetch('/api/posts'), fetch('/api/settings') ]); // Все данные загружены параллельно! return { users, posts, settings }; }

Обработка нескольких попыток:

async function fetchWithRetry(url, retries = 3) { for (let i = 0; i setTimeout(resolve, 1000 * (i + 1))); } } }

Итог

Асинхронное программирование – это основа Node.js. Разберитесь с промисами, а потом переходите к async/await, чтобы писать понятный и простой в поддержке код. Для начала:

  • Колбэки → для простых случаев и если нужна совместимость
  • Промисы → для сложных цепочек асинхронных операций
  • Async/Await → для современного и читаемого кода

Попрактикуйтесь на простых примерах, и очень скоро асинхронность станет вашим козырем в Node.js разработке!