Асинхронное программирование в JavaScript является критически важным
для работы с сетевыми запросами, таймерами, файловой системой и другими
операциями, которые могут занимать продолжительное время. Паттерн
async/await предоставляет синтаксический сахар поверх
промисов, делая асинхронный код более читаемым и управляемым.
async и awaitasync — модификатор функции, который
позволяет использовать внутри неё await. Любая функция,
объявленная как async, автоматически возвращает промис.
Даже если функция возвращает примитивное значение, оно оборачивается в
Promise.resolve().async function fetchData() {
return 42; // эквивалентно Promise.resolve(42)
}
await — оператор, который
приостанавливает выполнение функции до завершения промиса. Результат
выражения с await — значение, которое промис резолвит, либо
выбрасывается ошибка, если промис отклонён.async function getData() {
const result = await fetch('https://api.example.com/data');
const json = await result.json();
return json;
}
Последовательное выполнение: Когда несколько
асинхронных операций зависят друг от друга, используют
await в цепочке.
async function processSequential() {
const step1 = await fetchStep1();
const step2 = await fetchStep2(step1);
return step2;
}
Параллельное выполнение: Если операции независимы,
их лучше запускать одновременно с помощью Promise.all,
чтобы ускорить выполнение.
async function processParallel() {
const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);
return data1 + data2;
}
Ошибки в async/await ловятся с использованием блока
try/catch.
async function fetchWithErrorHandling() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) throw new Error('Network response was not ok');
const data = await response.json();
return data;
} catch (error) {
console.error('Ошибка при загрузке данных:', error);
throw error; // повторное выбрасывание ошибки
}
}
Для массовой обработки нескольких промисов удобно комбинировать
Promise.allSettled, чтобы получить статус всех промисов без
прерывания выполнения из-за одного отказавшего промиса.
async function fetchMultiple() {
const results = await Promise.allSettled([fetchData1(), fetchData2()]);
results.forEach((result) => {
if (result.status === 'fulfilled') {
console.log('Успешно:', result.value);
} else {
console.log('Ошибка:', result.reason);
}
});
}
async/awaitИспользование forEach с await может
приводить к неожиданным результатам, так как forEach не
поддерживает асинхронные функции корректно. Вместо этого применяют
for...of или map с
Promise.all.
const urls = ['url1', 'url2', 'url3'];
// Неправильно:
urls.forEach(async (url) => {
const data = await fetch(url);
console.log(await data.json());
});
// Правильно:
for (const url of urls) {
const response = await fetch(url);
const data = await response.json();
console.log(data);
}
// Или параллельно:
await Promise.all(urls.map(async (url) => {
const response = await fetch(url);
const data = await response.json();
console.log(data);
}));
async/await легко интегрируется с другими паттернами,
такими как декораторы, функции высшего
порядка и мемоизация. Например, можно создать
обёртку для логирования времени выполнения асинхронных функций:
function measureAsync(fn) {
return async function(...args) {
const start = Date.now();
const result = await fn(...args);
console.log(`Время выполнения: ${Date.now() - start} мс`);
return result;
};
}
const fetchDataMeasured = measureAsync(fetchData);
await fetchDataMeasured();
await — функция вернёт промис,
а не значение, что может нарушить логику.async блоков могут замедлить интерфейс, хотя сам
await не блокирует поток.then/catch и await иногда приводит к двойной
обработке ошибок.await без Promise.all может снижать
производительность.await только внутри async
функций.Promise.all для
повышения скорости.try/catch или
использовать Promise.allSettled.for...of для асинхронных циклов над
forEach.В работе с Lighthouse асинхронные функции широко применяются для:
launchChromeAndRunLighthouse.const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
async function runLighthouse(url, opts = {}) {
const chrome = await chromeLauncher.launch({chromeFlags: ['--headless']});
opts.port = chrome.port;
try {
const results = await lighthouse(url, opts);
console.log(results.lhr.categories.performance.score);
} finally {
await chrome.kill();
}
}
Использование async/await позволяет строить чистую,
читаемую цепочку запуска анализа, обработки результатов и корректного
завершения Chrome, что особенно важно при автоматизации тестов
производительности и SEO-аудитов.