Ответ
Задача: Обработка большого CSV-файла (сотни МБ) с трансформацией данных и записью результата в базу данных.
Наивное (медленное) решение: Загрузка всего файла в память.
const fs = require('fs');
const csv = require('csv-parser');
// Проблема: весь файл загружается в память
fs.readFile('huge-file.csv', 'utf8', (err, data) => {
if (err) throw err;
const lines = data.split('n');
const results = [];
lines.forEach(line => {
// Обработка каждой строки
const processed = transformLine(line);
results.push(processed);
});
// Массив results может занимать гигабайты памяти
saveToDatabase(results);
});
Оптимизированное решение с использованием Streams и пайплайнов:
const fs = require('fs');
const { pipeline } = require('stream');
const csv = require('csv-parser');
const { Transform } = require('stream');
// Кастомный Transform stream для обработки данных
const transformer = new Transform({
objectMode: true,
transform(chunk, encoding, callback) {
// Обработка одной строки CSV
const processed = {
id: chunk.id,
value: calculateValue(chunk),
timestamp: new Date()
};
callback(null, processed);
}
});
// Пайплайн: чтение → парсинг CSV → трансформация → запись в БД
pipeline(
fs.createReadStream('huge-file.csv'),
csv(),
transformer,
async function (source) {
for await (const chunk of source) {
// Пакетная запись в БД
await saveToDatabaseBatch(chunk);
}
},
(err) => {
if (err) {
console.error('Pipeline failed:', err);
} else {
console.log('Pipeline succeeded');
}
}
);
Ключевые оптимизации:
- Streams вместо загрузки в память — обрабатываем данные по частям.
- Backpressure управляется автоматически.
- Асинхронная обработка не блокирует Event Loop.
- Пакетная запись в БД уменьшает количество запросов.
Дополнительные подходы для CPU-heavy задач:
- Вынос тяжёлых вычислений в Worker Threads.
- Использование setImmediate() для разбивки долгих синхронных задач.