Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Синхронные операции в Node.js
Синхронные операции — это операции, которые блокируют Event Loop и выполняются последовательно. В production-среде их нужно минимизировать, но знать их важно.
1. Синхронные операции с файлами (fs module)
Файловые операции имеют как синхронную, так и асинхронную версию.
// ❌ СИНХРОННО (блокирует Event Loop)
const fs = require('fs');
const data = fs.readFileSync('file.txt', 'utf-8');
console.log(data); // Ждём, пока файл загрузится
// Весь код ниже ждёт завершения readFile
const size = fs.statSync('file.txt').size;
// ✅ АСИНХРОННО (не блокирует)
fs.readFile('file.txt', 'utf-8', (err, data) => {
console.log(data);
});
console.log('Это выполнится первым!');
Синхронные методы fs:
// Чтение
fs.readFileSync(path, encoding);
fs.readSync(fd, buffer, offset, length, position);
// Запись
fs.writeFileSync(path, data, encoding);
fs.appendFileSync(path, data);
// Информация
fs.statSync(path);
fs.lstatSync(path);
// Удаление
fs.unlinkSync(path);
fs.rmdirSync(path);
// Операции с директориями
fs.readdirSync(path);
mkdirSync(path);
2. Синхронные операции с криптографией
const crypto = require('crypto');
// ❌ СИНХРОННО
const hash = crypto.createHash('sha256');
hash.update('password');
const digest = hash.digest('hex'); // Быстро, но блокирует
// ✅ АСИНХРОННО (для тяжёлых операций)
const pbkdf2 = crypto.pbkdf2(
'password',
'salt',
100000,
32,
'sha256',
(err, key) => {
console.log(key); // Не блокирует Event Loop
}
);
// Синхронная версия
const keySync = crypto.pbkdf2Sync('password', 'salt', 100000, 32, 'sha256');
3. JSON парсинг/сериализация
// Синхронная операция (обычно быстрая)
const data = JSON.parse(jsonString);
const json = JSON.stringify(obj);
// Опасна только на ОЧЕНЬ больших данных (>10MB)
const largeData = JSON.parse(hugeJsonString); // Может заморозить
// Решение: парсить по кускам или использовать streaming
const { parser } = require('stream-json');
const fs = require('fs');
fs.createReadStream('huge.json')
.pipe(parser())
.on('data', (chunk) => {
console.log(chunk); // Не блокирует
});
4. Синхронная обработка массивов
// ❌ СИНХРОННО (блокирует если данных много)
const users = Array(10000000).fill(null).map((_, i) => ({
id: i,
name: `User ${i}`,
email: `user${i}@example.com`,
}));
// ✅ АСИНХРОННО (с помощью worker threads)
const { Worker } = require('worker_threads');
const worker = new Worker('./heavy-computation.js');
worker.on('message', (result) => {
console.log(result);
});
5. Синхронные вычисления (CPU-bound)
// ❌ СИНХРОННО (блокирует, если долгие вычисления)
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
const result = fibonacci(40); // Будет ждать долго, блокируя Event Loop
// ✅ АСИНХРОННО (через Worker Threads)
const { Worker } = require('worker_threads');
const path = require('path');
function runFibonacci(n) {
return new Promise((resolve, reject) => {
const worker = new Worker(path.resolve(__filename), {
workerData: n,
});
worker.on('message', resolve);
worker.on('error', reject);
});
}
await runFibonacci(40); // Не блокирует Event Loop
6. Синхронные операции require/import
// СИНХРОННО (но нормально, потому что обычно на старте)
const express = require('express');
const fs = require('fs');
const config = require('./config.json');
// Проблема: require('динамический путь')
const moduleName = getUserModule(); // 'postgres' или 'mysql'
const db = require(`./db/${moduleName}`); // Блокирует до загрузки
// Решение: асинхронно
const db = await import(`./db/${moduleName}.js`);
7. Синхронные операции с буферами
// СИНХРОННО
const buffer = Buffer.alloc(1000000); // Создание буфера
const copied = buffer.copy(otherBuffer); // Копирование
const str = buffer.toString('utf-8'); // Конвертирование
// На малых объёмах это нормально, но на больших может заморозить
8. Синхронная обработка в цикле
// ❌ СИНХРОННО (очень плохо)
for (let i = 0; i < 1000000; i++) {
const hash = crypto.createHash('sha256');
hash.update(`user${i}`);
hash.digest('hex'); // 1 миллион итераций, блокирует
}
// ✅ АСИНХРОННО (батчевание)
const batchSize = 100;
for (let i = 0; i < 1000000; i += batchSize) {
await Promise.all(
Array.from({ length: batchSize }).map((_, j) => {
const hash = crypto.createHash('sha256');
hash.update(`user${i + j}`);
return hash.digest('hex');
})
);
// Даём Event Loop обработать другие события
await new Promise(resolve => setImmediate(resolve));
}
9. Синхронные операции регулярных выражений
// СИНХРОННО
const regex = /([a-z]+)\d+/g;
const matches = largeString.match(regex); // На больших строках может зависнуть
// Проблема: ReDoS (Regular Expression Denial of Service)
const dangerous = /^(a|a)*$/; // Экспоненциальная сложность
const test = dangerous.test('aaaaaaaaaaaaaaaaaaab'); // Может зависнуть
// Решение: использовать timeout
const runWithTimeout = (fn, timeout) => {
return Promise.race([
fn(),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
),
]);
};
await runWithTimeout(
() => Promise.resolve(dangerous.test(str)),
1000
);
10. Синхронный доступ к памяти
// СИНХРОННО (обычно быстро)
const obj = {};
obj.key = 'value';
const val = obj.key;
// Проблема только если много операций на объекте
for (let i = 0; i < 10000000; i++) {
obj[`key${i}`] = i; // Может замедлить
}
// Решение: использовать Map для больших объёмов
const map = new Map();
for (let i = 0; i < 10000000; i++) {
map.set(`key${i}`, i); // Быстрее
}
Таблица синхронных операций
| Операция | Примерное время | Блокирует? | Решение |
|---|---|---|---|
| JSON.parse (10MB) | 100-500ms | Да | Streaming парсинг |
| fs.readFileSync (1MB) | 50-200ms | Да | fs.readFile |
| crypto.pbkdf2Sync | 100-500ms | Да | crypto.pbkdf2 (async) |
| Regex на 1MB | 10-100ms | Да | timeout + validation |
| Buffer copy (100MB) | 50-200ms | Да | stream.pipe |
| Object lookup | < 1ms | Нет | OK для small objects |
| Array iteration (1M) | 5-20ms | Да | Worker threads |
Общее правило
// Если операция займёт > 10ms, рассмотри асинхронность
function isBig(operation) {
const start = performance.now();
operation();
const duration = performance.now() - start;
return duration > 10; // Если > 10ms, это проблема
}
Best Practice
// ✅ Хорошо: минимум синхронных операций
app.get('/api/data', async (req, res) => {
// Асинхронно
const data = await db.query('SELECT ...');
const processed = await processLargeData(data);
res.json(processed);
});
// ❌ Плохо: много синхронных операций
app.get('/api/data', (req, res) => {
// Синхронно (блокирует Event Loop)
const data = fs.readFileSync('data.json');
const parsed = JSON.parse(data);
const result = heavyComputation(parsed);
res.json(result);
});
Вывод: в Node.js синхронные операции необходимы, но их нужно тщательно использовать. Операции < 1ms можно оставлять синхронными, операции > 10ms должны быть асинхронными.