Ответ
В Node.js я использую несколько подходов для работы с Promise в зависимости от контекста:
1. Async/await (рекомендуемый подход)
async function getUserData(userId) {
try {
// Ждем выполнение промиса
const user = await User.findById(userId);
// Параллельное выполнение независимых промисов
const [orders, settings, logs] = await Promise.all([
Order.find({ userId }),
UserSettings.findOne({ userId }),
AccessLog.find({ userId }).limit(10)
]);
return { user, orders, settings, logs };
} catch (error) {
console.error('Failed to fetch user data:', error);
throw new Error(`User data unavailable: ${error.message}`);
}
}
2. Promise chaining для последовательных операций
function processUpload(filePath) {
return validateFile(filePath)
.then(metadata => resizeImage(metadata))
.then(resized => uploadToS3(resized))
.then(s3Url => saveToDatabase(s3Url))
.then(result => {
console.log('Upload completed:', result.id);
return result;
})
.catch(error => {
console.error('Upload pipeline failed:', error);
cleanupTempFiles(filePath);
throw error;
});
}
3. Ожидание нескольких промисов с разными стратегиями
async function fetchWithFallbacks(urls) {
// Promise.race - первый успешный или ошибочный
const fastest = await Promise.race(urls.map(url => fetch(url)));
// Promise.allSettled - все, независимо от результата
const allResults = await Promise.allSettled(
urls.map(url => fetch(url).then(r => r.json()))
);
const successful = allResults
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
return { fastest: await fastest.json(), successful };
}
4. Ожидание в не-async контекстах
// В обработчике события или callback
server.on('request', (req, res) => {
// Используем IIFE (Immediately Invoked Function Expression)
(async () => {
try {
const data = await processRequest(req);
res.writeHead(200);
res.end(JSON.stringify(data));
} catch (error) {
res.writeHead(500);
res.end('Internal Server Error');
}
})();
});
// Или с .then() в цепочке
readFilePromise('config.json')
.then(config => startServer(config))
.then(server => {
console.log('Server started on port', server.port);
return server;
})
.catch(error => {
console.error('Failed to start server:', error);
process.exit(1);
});
5. Top-level await (Node.js 14.8+)
// В ES-модулях можно использовать await на верхнем уровне
import { connectToDatabase } from './db.js';
const db = await connectToDatabase();
console.log('Database connected');
export { db };
Из моего опыта:
- Всегда обрабатываю ошибки через try/catch с async/await
- Для параллельных независимых операций использую
Promise.all() - Для операций, где нужен первый результат, использую
Promise.race()с timeout - В legacy-коде с callback иногда использую
util.promisify() - Избегаю смешивания async/await и .then() в одной функции для читаемости
Ответ 18+ 🔞
Слушай, ну это ж классика, блядь! Node.js и промисы — это как водка и закуска, одно без другого нихуя не работает. Я тебе сейчас разложу по полочкам, как я с этим добром вожусь, чтобы голова не болела.
1. Async/await — это наше всё, ёпта
async function getUserData(userId) {
try {
// Ждём, пока промис отстреляет
const user = await User.findById(userId);
// А тут делаем овердохуища запросов параллельно
const [orders, settings, logs] = await Promise.all([
Order.find({ userId }),
UserSettings.findOne({ userId }),
AccessLog.find({ userId }).limit(10)
]);
return { user, orders, settings, logs };
} catch (error) {
console.error('Не вышло достать данные юзера:', error);
throw new Error(`Данные пользователя недоступны: ${error.message}`);
}
}
2. Цепочки промисов для последовательного говна
function processUpload(filePath) {
return validateFile(filePath)
.then(metadata => resizeImage(metadata))
.then(resized => uploadToS3(resized))
.then(s3Url => saveToDatabase(s3Url))
.then(result => {
console.log('Загрузка завершена:', result.id);
return result;
})
.catch(error => {
console.error('Всё накрылось медным тазом:', error);
cleanupTempFiles(filePath);
throw error;
});
}
3. Ждём несколько промисов по-разному, как хитрая жопа
async function fetchWithFallbacks(urls) {
// Promise.race — кто первый, того и тапки
const fastest = await Promise.race(urls.map(url => fetch(url)));
// Promise.allSettled — всем сестрам по серьгам
const allResults = await Promise.allSettled(
urls.map(url => fetch(url).then(r => r.json()))
);
const successful = allResults
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
return { fastest: await fastest.json(), successful };
}
4. Ожидание там, где async нельзя, блядь
// В каком-нибудь обработчике события
server.on('request', (req, res) => {
// Используем IIFE, чтоб не бздеть
(async () => {
try {
const data = await processRequest(req);
res.writeHead(200);
res.end(JSON.stringify(data));
} catch (error) {
res.writeHead(500);
res.end('Сервер ебнулся');
}
})();
});
// Или старым добрым .then()
readFilePromise('config.json')
.then(config => startServer(config))
.then(server => {
console.log('Сервер запущен на порту', server.port);
return server;
})
.catch(error => {
console.error('Сервер не взлетел:', error);
process.exit(1);
});
5. Top-level await (Node.js 14.8+) — красота, ядрёна вошь!
// В ES-модулях можно на самом верху await впендюрить
import { connectToDatabase } from './db.js';
const db = await connectToDatabase();
console.log('База подключена');
export { db };
Из моего горького опыта, чувак:
- Всегда ловлю ошибки через try/catch, а то будет тебе хиросима
- Для параллельного говна —
Promise.all(), ебать копать - Если нужен первый результат —
Promise.race()с таймаутом, чтоб не ждать вечность - В старом коде иногда
util.promisify()выручает, как палочка-выручалочка - Стараюсь не мешать async/await и .then() в одной функции — а то получается пиздопроебина, в которой нихуя не разберёшься