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

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

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

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

const fs = require('fs')

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

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

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

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

const fs = require('fs')

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

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

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

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

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

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.

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

  console.log(fileContent)
})