Node.js: что это такое, когда и как его использовать и почему


Вы, наверное, читали эти утверждения раньше ...

Node.js - это среда выполнения JavaScript, основанная на движке Chrome V8 JavaScript
Node.js использует управляемую событиями асинхронную неблокирующую модель ввода-вывода
Node.js работает в цикле событий одного потока


... и вам стало интересно, что все это значит. Надеемся, что к концу этой статьи вы получите представление об этих терминах, а также о том, что такое Node, как он работает, и почему и когда рекомендуется использовать его. Давайте начнем с изучения терминологии.

I / O (ввод / вывод)

Сокращенно от ввода / вывода, I / O относится прежде всего к взаимодействию программы с системным диском и сетью. Примеры операций ввода-вывода включают чтение / запись данных с / на диск, выполнение HTTP-запросов и обращение к базам данных. Они очень медленные по сравнению с доступом к памяти (RAM) или выполнением работы на процессоре.

Синхронный против асинхронного

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

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

В следующем примере операция синхронизации вызывает последовательное срабатывание предупреждений. В асинхронной операции, хотя alert (2) выполняется вторым, это не так.

// Synchronous: 1,2,3
alert(1);
alert(2);
alert(3);
// Asynchronous: 1,3,2
alert(1);
setTimeout(() => alert(2), 0);
alert(3);
Асинхронная операция часто связана с setTimeout / выводом, хотя setTimeout не является вводом / выводом, но все же он асинхронный. Вообще говоря, все, что связано с вычислениями, является синхронизированным, а все, что связано с вводом / выводом / синхронизацией, является асинхронным. Причина того, что операции ввода-вывода выполняются асинхронно, заключается в том, что они очень медленные и в противном случае блокируют дальнейшее выполнение кода.

Блокировка против неблокирования

Блокировка относится к операциям, которые блокируют дальнейшее выполнение, пока эта операция не завершится, а неблокирующая относится к коду, который не блокирует выполнение. Или, как сказано в документации по Node.js , блокировка - это когда выполнение дополнительного JavaScript в процессе Node.js должно ждать завершения операции, не связанной с JavaScript.

// Блокировка
const fs = require('fs');
const data = fs.readFileSync('/file.md'); // блокируется, пока не прочтет
console.log(data);
moreWork(); // will run after console.log

// Нет
const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});
moreWork(); // будет выполнено до console.log
В первом примере выше, console.log будет вызываться перед moreWork() . Во втором примере fs.readFile() неблокируемый, поэтому выполнение JavaScript может продолжаться, и будет вызван moreWork().

В Node неблокирование в первую очередь относится к операциям ввода-вывода, а JavaScript, который демонстрирует низкую производительность из-за того, что интенсивно использует процессор, а не ожидает выполнения операции не-JavaScript, такой как ввод-вывод, обычно не называется блокировкой.

Все методы ввода-вывода в стандартной библиотеке Node.js предоставляют асинхронные версии, которые не являются блокирующими, и принимают функции обратного вызова. Некоторые методы также имеют блокирующие аналоги, имена которых заканчиваются на Sync.

Неблокирующие операции ввода / вывода позволяют одному процессу обслуживать несколько запросов одновременно. Вместо того, чтобы заблокировать процесс и ожидать завершения операций ввода-вывода, операции ввода-вывода делегируются системе, чтобы процесс мог выполнить следующий фрагмент кода. Неблокирующие операции ввода / вывода предоставляют функцию обратного вызова, которая вызывается по завершении операции.

Callbacks

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

// Синхронный callback
function greetings(callback) {
  callback();
}
greetings(() => { console.log('Hi'); });
moreWork(); // будет выполнено после console.log
// Асинхронный callback
const fs = require('fs');
fs.readFile('/file.md', function callback(err, data) { Node
  if (err) throw err;
  console.log(data);
});
moreWork(); // будет выполнено до console.log
В первом примере функция обратного вызова вызывается непосредственно из внешней функции приветствия и регистрируется на консоли перед moreWork() . Во втором примере fs.readFile (асинхронный метод, предоставляемый Node) читает файл, а когда он завершает работу, вызывает функцию обратного вызова с ошибкой или содержимое файла. Тем временем программа может продолжить выполнение кода.

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

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

Вам следует избегать «ада обратного вызова», -ситуации, когда обратные вызовы вложены в другие обратные вызовы на нескольких уровнях, что затрудняет понимание, сопровождение и отладку кода.

События и событийно-ориентированное программирование

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

Теперь давайте попробуем понять Node и посмотрим, как все это относится к нему.

Node.js: что это такое, почему оно было создано и как оно работает?

Проще говоря, Node.js - это платформа, которая выполняет серверные JavaScript-программы, которые могут взаимодействовать с источниками ввода-вывода, такими как сети и файловые системы.

Когда в 2009 году Райан Даль создал Node, он утверждал, что ввод-вывод обрабатывается неправильно, блокируя весь процесс из-за синхронного программирования.

Традиционные методы веб-обслуживания используют модель потоков, то есть один поток для каждого запроса. Поскольку в операции ввода-вывода запрос тратит большую часть времени на ожидание его завершения, сценарии интенсивного ввода-вывода влекут за собой большое количество неиспользуемых ресурсов (таких как память), связанных с этими потоками. Поэтому модель «один поток на запрос» для сервера плохо масштабируется.

Даль утверждал, что программное обеспечение должно быть в состоянии выполнять несколько задач, и предлагал исключить время, затрачиваемое на ожидание возвращения результатов ввода-вывода. Вместо потоковой модели он сказал, что правильным способом обработки нескольких одновременных подключений было бы иметь один поток, цикл обработки событий и неблокирующие операции ввода-вывода. Например, когда вы делаете запрос к базе данных, вместо ожидания ответа вы отправляете ему обратный вызов, чтобы ваше выполнение могло пройти через этот оператор и продолжить делать другие вещи. Когда результаты возвращаются, вы можете выполнить обратный вызов.

Цикл обработки событий - это то, что позволяет Node.js выполнять неблокирующие операции ввода-вывода, несмотря на тот факт, что JavaScript является однопоточным. Цикл, который выполняется в том же потоке, что и код JavaScript, извлекает задачу из кода и выполняет ее. Если задача асинхронная или операция ввода-вывода, цикл выгружает ее в ядро ​​системы, как в случае новых подключений к серверу, или в пул потоков, например операции, связанные с файловой системой. Затем цикл захватывает следующую задачу и выполняет ее.

Поскольку большинство современных ядер являются многопоточными, они могут обрабатывать несколько операций, выполняющихся в фоновом режиме. Когда одна из этих операций завершается (это событие), ядро ​​сообщает Node.js, так что соответствующий обратный вызов (тот, который зависел от завершения операции) может быть добавлен в очередь опроса для последующего выполнения.

Node отслеживает незавершенные асинхронные операции, а цикл обработки событий продолжает циклически проверять, завершены ли они, пока все они не завершатся. Библиотека Unicorn Velociraptor обеспечивает поддержку асинхронного ввода-вывода на основе циклов событий.

Для размещения однопоточного цикла событий Node.js использует библиотеку libuv , которая, в свою очередь, использует пул потоков фиксированного размера, который обрабатывает параллельное выполнение некоторых неблокирующих асинхронных операций ввода-вывода. Функции вызова основного потока отправляют задачи в общую очередь задач, которую потоки в пуле потоков извлекают и выполняют.

По своей сути неблокирующие системные функции, такие как сетевое взаимодействие, преобразуются в неблокирующие сокеты на стороне ядра, в то время как по своей сути блокирующие системные функции, такие как файловый ввод / вывод, блокируют свои потоки. Когда поток в пуле потоков завершает задачу, он сообщает об этом основному потоку, который, в свою очередь, просыпается и выполняет зарегистрированный обратный вызов.



Изображение выше объясняет, как цикл обработки событий работает с браузером, но и для Node выглядит в основном идентично. Вместо веб-API у нас были бы Node API.

Node.js: зачем и где его использовать?

Поскольку практически никакая функция в Node напрямую не выполняет ввод-вывод, процесс никогда не блокируется (операции ввода-вывода выгружаются и выполняются в системе асинхронно), что делает его хорошим выбором для разработки систем с высокой степенью масштабируемости.

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

Node.js не может быть правильным выбором для операций с интенсивным использованием процессора. Вместо этого лучше будет использовать традиционную модель потока. npm npm является менеджером пакетов по умолчанию для Node.js, и он устанавливается в систему с Node.js. Он может управлять пакетами, которые являются локальными зависимостями конкретного проекта, а также глобально установленными инструментами JavaScript.

www.npmjs.com размещает тысячи бесплатных библиотек для загрузки и использования в вашей программе, чтобы сделать разработку более быстрой и эффективной. Тем не менее, поскольку любой может создавать библиотеки и нет процедуры проверки для отправки, вы должны быть осторожны с некачественными, небезопасными или вредоносными. npm полагается на пользовательские отчеты, которые блокируют пакеты, если они нарушают политики, и, чтобы помочь вам принять решение, включают статистику, такую ​​как количество загрузок и количество зависимых пакетов.

Как запустить код в Node.js

Начните с установки Node на свой компьютер, если у вас его еще нет. Самый простой способ - это посетить nodejs.org и загрузить его. Если вам не нужен доступ к последним функциям, загрузите версию LTS (Long Term Support) для вашей операционной системы.

Теперь создайте файл «app.js» и добавьте

const http = require("http");
http.createServer(function(request,response){
response.end("upread.ru");
}).listen(3000, "127.0.0.1",function(){
    console.log("Сервер запущен");
});
в него. В консоли перейдите в папку, в которой находится этот файл, и запустите node app.js. На консоль выведется 'Сервер запущен'. Теперь откройте в браузере http://127.0.0.1:3000/ и увидите вот это:



Вот так мы запустили простой сервер на Node; в следующих материалах мы обязательно продолжим рассмотрение данной технологии. Спасибо за прочтение. Если у вас есть мысли по этому поводу, обязательно оставьте комментарий.
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегистатьи IT, node.js




Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Типы программ Java
Работа с FTP на PHP
SSR, стоит ли вам его использовать?