Какие есть варианты переписать функцию чтения файла с учетом асинхронности
Что проверяют
Понимаете ли вы, чем асинхронное чтение отличается от синхронного и почему fs.readFileSync или тяжёлая обработка файла блокируют поток. Следом обычно спрашивают, что делать с файлом на несколько гигабайт или с десятком файлов сразу.
Как отвечать
Покажите эволюцию подходов и среду, где каждый работает:
- колбэк:
fs.readFile(path, 'utf8', (err, data) => ...)в Node.js. Работает, но при вложенности превращается в лестницу, а ошибку легко не проверить; - промисы:
readFileизnode:fs/promisesили обёрткаutil.promisify(fs.readFile). Сasync/awaitкод читается сверху вниз, ошибки ловятся обычнымtry/catch, а чтение можно отменить черезsignalотAbortController; - потоки:
fs.createReadStreamи перебор черезfor await. Файл обрабатывается кусками, память не растёт вместе с его размером; FileReaderв браузере: событийный API, его оборачивают вnew Promise, подписываясь и наonload, и наonerror;- методы
Blob:FileнаследуетBlob, поэтому у файла из<input type="file">естьfile.text(),file.arrayBuffer()иfile.stream(). Они сразу возвращают промис или поток, сегодня это самый короткий вариант; - Web Worker: если после чтения идёт тяжёлый разбор, например CSV на сотни тысяч строк, его выносят в воркер. Иначе интерфейс подвиснет, хотя само чтение асинхронное.
Для нескольких файлов назовите Promise.all или Promise.allSettled, если падение одного не должно ронять остальные. Последовательный await в цикле тоже работает, но медленнее без причины.
Где спотыкаются
Оборачивают readFileSync в async-функцию и считают её асинхронной. Ключевое слово не делает блокирующий вызов неблокирующим.
Ловят ошибку, пишут её в консоль и возвращают undefined. Вызывающий код получает «успех» без данных. Ошибку нужно пробросить или вернуть осмысленное значение.
Читают большой файл целиком в память. На гигабайтном логе это кончится падением процесса или вкладки, здесь нужны потоки.