Асинхронная работа с fs через коллбэки в NodeJS


Давайте теперь рассмотрим асинхронную работу с файловой системой. Как правило, в NodeJS все методы модуля fs существуют в двух вариантах: в синхронном и асинхронном.

Например, для синхронного чтения файла используется метод readFileSync, а для асинхронного - readFile. Аналогично для записи файла существует пара writeFileSync и writeFile.

Асинхронное чтение файла
Метод readFile первым параметром принимает имя или путь к файлу, вторым параметром - кодировку, а третьим - коллбэк, который выполнится после чтения файла.

В коллбэк следует передавать два параметра. В первый параметр попадет объект с ошибкой, если она произойдет, а во второй - текст прочитанного файла.

Давайте для примера прочитаем текст какого-нибудь файла:

fs.readFile('readme.txt', 'utf8', function(err, data) {
console.log(data);
});

Проверка асинхронности
Можно убедится в том, что чтение файла происходит асинхронно. Для этого выведем что-нибудь в консоль после работы с методом readFile:

fs.readFile('readme.txt', 'utf8', function(err, data) {
console.log(data);
});

console.log('!!!');
Как вы уже знаете, коллбэк выполнится, когда файл будет прочитан. А пока файл читается, код скрипта будет выполнятся дальше. Это значит, что в консоли сначала появится результат второго console.log, а потом первого.

Обработка исключительных ситуаций
Так как наш код асинхронный, то исключительные ситуации нельзя поймать через try-catch. Для обработки исключений в коллбэке предназначен первый параметр. Этот параметр будет содержать null, если исключения не случилось, или объект с ошибкой, если исключение произошло.

Давайте допишем код коллбэка так, чтобы он обрабатывал исключительные ситуации:

fs.readFile('readme.txt', 'utf8', function(err, data) {
if (!err) {
console.log(data);
} else {
console.log('ошибка', err);
}
});

Асинхронная запись файла
Асинхронная запись текста в файл выполняется аналогично:

fs.writeFile('readme.txt', 'text', function(err) {
if (err) {
console.log('ошибка');
}
});

Асинхронное чтение нескольких файлов
Пусть у нас есть два файла с числами. Давайте найдем произведение этих чисел. Очевидно, что для этого нам нужно прочитать оба этих файла.

Но, так как код асинхронный, нам нужно читать второй файл в коллбэке первого:

fs.readFile('readme1.txt', 'utf8', function(err, data1) {
if (!err) {
fs.readFile('readme2.txt', 'utf8', function(err, data2) {
if (!err) {
console.log(data1 * data2);
} else {
console.log('ошибка чтения файла readme2');
}
});
} else {
console.log('ошибка чтения файла readme1');
}
});

Асинхронное чтение и запись файла
Предположим нам нужно прочитать файл, сделать его текстом операцию и записать обратно в этот или другой файл. В этом случае запись в файл нужно будет делать в коллбэке чтения:

fs.readFile('readme.txt', 'utf8', function(err, data) {
if (!err) {
fs.writeFile('readme.txt', data + '!', function(err) {
if (err) {
console.log('ошибка записи файла');
}
});
} else {
console.log('ошибка чтения файла');
}
});

Стрелочные функции
Как правило коллбэки в NodeJS делают с помощью стрелочных функций. Это сокращает код, но несколько затрудняет понимание с непривычки.

Давайте переделаем предыдущий код на стрелочные функции:

fs.readFile('readme.txt', 'utf8', (err, data) => {
if (!err) {
fs.writeFile('readme.txt', data + '!', err => {
if (err) {
console.log('ошибка записи файла');
}
});
} else {
console.log('ошибка чтения файла');
}
});