Чем заменить deprecated fs.exists и почему его выпиливают из ноды?nodejs-7

Почему fs.exists стал deprecated?

  1. Проблемы с race condition:
    • Между проверкой существования файла (exists()) и последующей операцией (open(), readFile() и т.д.) файл может быть удален/изменен
    • Это классическая TOCTOU-уязвимость (Time of Check to Time of Use)
// Проблемный код:
if (fs.existsSync('file.txt')) {
  // Файл может быть удален здесь!
  fs.readFile('file.txt', (err, data) => {...});
}
  1. Асинхронный API не соответствует Node.js стилю:

    • Оригинальный fs.exists() использовал нестандартный callback (без ошибки первым аргументом)
    • Противоречит error-first callback конвенции Node.js
  2. Избыточность:

    • Большинство файловых операций уже возвращают ошибку ENOENT если файла нет
    • Отдельная проверка существования обычно не нужна

Рекомендуемые альтернативы

1. Прямое использование операций с обработкой ошибок

Лучший подход — просто выполнять нужную операцию и обрабатывать ошибку:

fs.readFile('file.txt', (err, data) => {
  if (err && err.code === 'ENOENT') {
    // Файл не существует
  } else if (err) {
    // Другая ошибка
  } else {
    // Работа с данными
  }
});

2. fs.access/fs.accessSync

Для случаев, когда действительно нужно проверить доступ:

// Асинхронная версия
fs.access('file.txt', fs.constants.F_OK, (err) => {
  if (err) {
    console.log('Файл не существует');
  } else {
    console.log('Файл доступен');
  }
});

// Синхронная версия
try {
  fs.accessSync('file.txt', fs.constants.F_OK);
  console.log('Файл доступен');
} catch (err) {
  console.log('Файл не существует');
}

3. fs.promises.access

async function checkFileExists(file) {
  try {
    await fs.promises.access(file, fs.constants.F_OK);
    return true;
  } catch {
    return false;
  }
}

Когда действительно нужно проверять существование?

Редкие случаи, когда уместна проверка:

  1. Проверка перед созданием файла (чтобы не перезаписать существующий)
  2. Проверка доступности файла для UI/логики приложения
  3. Кеширование информации о существовании файлов

Резюмируем

  1. Не используйте fs.exists()/fs.existsSync() — они deprecated не просто так
  2. Основные альтернативы:
    • Прямые операции с обработкой ENOENT
    • fs.access() для явной проверки
    • Promise-версии в современном коде
  3. Лучшая практика — проектируйте код так, чтобы не требовалась отдельная проверка существования
  4. Причины отказа от exists():
    • Проблемы с race condition
    • Нестандартный callback API
    • Избыточность в большинстве случаев

Правильный подход — всегда учитывать возможность ошибки при работе с файловой системой, а не делать предварительные проверки.