← Назад к вопросам

Когда допустимо использовать синхронные методы для работы с файловой системой?

2.0 Middle🔥 141 комментариев
#Node.js и JavaScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Когда допустимо использовать синхронные методы для работы с файловой системой?

Синхронные методы файловой системы (fs.readFileSync(), fs.writeFileSync() и т.д.) допустимо использовать только в ограниченных случаях, так как они блокируют выполнение всего приложения.

Когда МОЖНО использовать синхронные методы

// ✓ 1. Инициализация приложения (startup)
const config = require('fs').readFileSync('./config.json', 'utf-8');
const settings = JSON.parse(config);

// ✓ 2. Загрузка переменных окружения
const env = require('fs').readFileSync('.env', 'utf-8');
require('dotenv').parse(env);

// ✓ 3. Чтение статических данных при запуске
const DATA = JSON.parse(fs.readFileSync('./data.json'));

// ✓ 4. Проверка наличия файла в начале
if (!fs.existsSync('./required-file.txt')) {
  throw new Error('Required file not found');
}

// ✓ 5. CLI утилиты (не веб-сервер)
const input = fs.readFileSync('/dev/stdin', 'utf-8');
console.log(process.argv);

Когда НЕЛЬЗЯ использовать синхронные методы

// ✗ 1. В обработчиках HTTP запросов
app.get('/users/:id', (req, res) => {
  // ПЛОХО! Блокирует весь сервер
  const userData = fs.readFileSync('./users.json');
  res.json(userData);
});

// ПРАВИЛЬНО — асинхронно
app.get('/users/:id', async (req, res) => {
  const userData = await fs.promises.readFile('./users.json');
  res.json(userData);
});

// ✗ 2. В цикле
users.forEach(user => {
  // ПЛОХО! Блокирует на каждую итерацию
  const file = fs.readFileSync(`./users/${user.id}.json`);
});

// ✗ 3. В middleware Express
app.use((req, res, next) => {
  // ПЛОХО! Каждый запрос блокирует
  const token = fs.readFileSync('./auth-key.txt');
  next();
});

// ✗ 4. В event handlers
emitter.on('event', () => {
  // ПЛОХО! Блокирует обработку других событий
  fs.readFileSync('./log.txt');
});

Почему это плохо?

const fs = require('fs');
const express = require('express');
const app = express();

// ПЛОХОЙ ПРИМЕР
app.get('/data', (req, res) => {
  console.log('1. Request начала');
  const data = fs.readFileSync('./huge-file.json'); // Блокирует на 5 секунд
  console.log('2. Data прочитана');
  res.json(data);
});

setInterval(() => {
  console.log('3. Interval fired');
}, 1000);

// Консоль:
// 1. Request начала
// [5 секунд молчания - весь сервер заморожен]
// 2. Data прочитана
// 3. Interval fired (только после разморозки)

Правильный подход

const fs = require('fs');
const express = require('express');
const app = express();

// ✓ ХОРОШИЙ ПРИМЕР
app.get('/data', async (req, res) => {
  try {
    console.log('1. Request начала');
    const data = await fs.promises.readFile('./huge-file.json');
    console.log('2. Data прочитана (без блокировки)');
    res.json(JSON.parse(data));
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

setInterval(() => {
  console.log('3. Interval fired');
}, 1000);

// Консоль:
// 1. Request начала
// 3. Interval fired (одновременно!)
// 2. Data прочитана
// 3. Interval fired

Синхронные методы при инициализации

// config.loader.js
const fs = require('fs');

class ConfigLoader {
  static load() {
    const configPath = process.env.CONFIG_PATH || './config.json';
    const rawConfig = fs.readFileSync(configPath, 'utf-8');
    return JSON.parse(rawConfig);
  }
}

// app.js
const CONFIG = ConfigLoader.load(); // Один раз при старте

app.get('/api/settings', (req, res) => {
  res.json(CONFIG);
});

Альтернативы синхронным методам

// ✗ Синхронный
const data = fs.readFileSync('./file.json');

// ✓ Callback
fs.readFile('./file.json', (err, data) => {
  if (err) console.error(err);
});

// ✓ Promise
fs.promises.readFile('./file.json')
  .then(data => console.log(data))
  .catch(err => console.error(err));

// ✓ Async/await (лучший вариант)
async function load() {
  try {
    const data = await fs.promises.readFile('./file.json');
    return data;
  } catch (error) {
    console.error(error);
  }
}

Правило

Синхронные операции допусти только:

  • При инициализации приложения
  • В CLI утилитах и скриптах
  • Для проверок перед стартом

Во всех остальных случаях используй асинхронные методы (fs.promises, async/await).