Перейти к содержанию

Блокирующие и неблокирующие вызовы

Блокирующими считаются те операции, при выполнении которых процесс Node.js вынужден ждать ее окончания, прежде чем начать выполнять следующий код. Это происходит из-за того, что приостанавливается работа event loop.

Большинство синхронных методов в Node.js относятся к блокирующим, и чаще всего они выполняют операции ввода/вывода или работают с сетью. Практически все синхронные методы имеют в своем названии Sync.

1
2
3
4
const fs = require('fs');

console.log(fs.readFileSync('./file.txt'));
console.log('After reading file');

Здесь с началом чтения файла file.txt процесс блокируется и продолжает работу только с завершением операции чтения. Результат работы приведенного кода.

1
2
{содержимое файла}
After reading file

Чтобы избежать блокировки event loop и тем самым создавать высокопроизводительные Node.js приложения, используйте асинхронные методы. Почти наверняка каждому синхронному блокирующему методу соответствует метод с точно таким же функционалом, но асинхронный.

1
2
3
4
5
6
7
const fs = require('fs');

fs.readFile('./file.txt', (err, data) => {
    if (err) throw err;
    console.log(data);
});
console.log('Before reading file');

В этом примере процесс не будет дожидаться окончания чтения файла, а продолжит выполнять следующий код. А когда содержимое файла будет получено - вызовет переданную методу readFile() callback-функцию. Результат работы кода примера.

1
2
Before reading file
{содержимое файла}

Синхронные методы блокируют процесс выполнения, асинхронные - нет.

Самая распространенная ошибка при использовании асинхронных методов - полагать, что следующий за методом код будет выполнен после его завершения.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const fs = require('fs');

let fileContent;

fs.readFile('./file.txt', (err, data) => {
    if (err) throw err;
    fileContent = data;
});

console.log(fileContent);

Здесь в консоль будет выведено undefined, поскольку в момент вывода значения переменной fileContent операция чтения еще не будет завершена. Чтобы избежать этого, необходимо занести код вывода содержимого файла в callback-функцию метода readFile() или создать Promise.

1
2
3
4
5
6
fs.readFile('./file.txt', (err, data) => {
    if (err) throw err;
    fileContent = data;

    console.log(fileContent);
});