Что такое Node.js? Объяснение среды выполнения JavaScript

Масштабируемость, время ожидания и пропускная способность - ключевые показатели производительности веб-серверов. Поддерживать низкую задержку и высокую пропускную способность при увеличении и уменьшении масштабов непросто. Node.js - это среда выполнения JavaScript, которая обеспечивает низкую задержку и высокую пропускную способность за счет «неблокирующего» подхода к обслуживанию запросов. Другими словами, Node.js не тратит время и ресурсы на ожидание возврата запросов ввода-вывода.

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

Хотя порождение потоков требует меньше памяти и ресурсов ЦП, чем процессы разветвления , оно все же может быть неэффективным. Наличие большого количества потоков может привести к тому, что сильно загруженная система будет тратить драгоценные циклы на планирование потоков и переключение контекста, что увеличивает задержку и накладывает ограничения на масштабируемость и пропускную способность.

Node.js использует другой подход. Он запускает однопоточный цикл обработки событий, зарегистрированный в системе, для обработки подключений, и каждое новое подключение вызывает срабатывание функции обратного вызова JavaScript . Функция обратного вызова может обрабатывать запросы с неблокирующими вызовами ввода-вывода и, при необходимости, может порождать потоки из пула для выполнения блокирующих или ресурсоемких операций и для балансировки нагрузки между ядрами ЦП. Подход Node к масштабированию с помощью функций обратного вызова требует меньше памяти для обработки большего количества подключений, чем большинство конкурирующих архитектур, масштабируемых с помощью потоков, включая Apache HTTP Server, различные серверы приложений Java, IIS и ASP.NET и Ruby on Rails.

Node.js оказывается весьма полезным не только для серверов, но и для настольных приложений. Также обратите внимание, что приложения Node не ограничиваются чистым JavaScript. Вы можете использовать любой язык, который транслируется в JavaScript, например TypeScript и CoffeeScript. Node.js включает движок JavaScript Google Chrome V8, который поддерживает синтаксис ECMAScript 2015 (ES6) без необходимости использования транспилятора ES6 в ES5, такого как Babel.

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

Немного истории JavaScript

В 1995 году Брендан Эйх, в то время подрядчик Netscape, создал язык JavaScript для работы в веб-браузерах - как гласит история, за 10 дней. Изначально JavaScript был предназначен для включения анимации и других манипуляций с объектной моделью документа браузера (DOM). Вскоре после этого была представлена ​​версия JavaScript для Netscape Enterprise Server.

Название JavaScript было выбрано в маркетинговых целях, так как в то время язык Java Sun был широко разрекламирован. Фактически, язык JavaScript был основан в основном на языках Scheme и Self с поверхностной семантикой, подобной Java.

Первоначально многие программисты отклоняли JavaScript как бесполезный для «реальной работы», потому что его интерпретатор работал на порядок медленнее, чем компилируемые языки. Ситуация изменилась, когда несколько исследований, направленных на ускорение JavaScript, начали приносить плоды. Наиболее заметно то, что движок JavaScript Google Chrome V8 с открытым исходным кодом, который выполняет своевременную компиляцию, встраивание и динамическую оптимизацию кода, может фактически превзойти код C ++ для некоторых нагрузок и превзойти Python для большинства случаев использования.

Платформа Node.js на основе JavaScript была представлена ​​в 2009 году Райаном Далем для Linux и MacOS в качестве более масштабируемой альтернативы HTTP-серверу Apache. NPM, написанный Исааком Шлютером, запущен в 2010 году. Нативная версия Node.js для Windows дебютировала в 2011 году.

Joyent владел, управлял и поддерживал разработку Node.js в течение многих лет. В 2015 году проект Node.js был передан Фонду Node.js и стал управляться техническим руководящим комитетом фонда. Node.js также был принят как совместный проект Linux Foundation. В 2019 году Node.js Foundation и JS Foundation объединились и образовали OpenJS Foundation.

Базовая архитектура Node.js

На высоком уровне Node.js сочетает в себе движок Google V8 JavaScript, однопоточный неблокирующий цикл событий и низкоуровневый API ввода-вывода. Урезанный пример кода, показанный ниже, иллюстрирует базовый шаблон HTTP-сервера с использованием стрелочных функций ES6 (анонимные лямбда-функции, объявленные с помощью оператора жирной стрелки =>) для обратных вызовов.

В начале кода загружается модуль HTTP, для hostnameпеременной сервера устанавливается значение localhost(127.0.0.1), а для portпеременной устанавливается значение 3000. Затем создается сервер и функция обратного вызова, в данном случае функция жирной стрелки, которая всегда возвращает одно и то же. ответ на любой запрос: statusCode200 (успех), текстовый тип содержимого и текстовый ответ ”Hello World\n”. Наконец, он сообщает серверу прослушивать localhostпорт 3000 (через сокет) и определяет обратный вызов для печати сообщения журнала на консоли, когда сервер начал прослушивание. Если вы запустите этот код в терминале или консоли с помощью nodeкоманды, а затем перейдете к localhost: 3000 с помощью любого веб-браузера на том же компьютере, вы увидите «Hello World» в своем браузере. Чтобы остановить сервер, нажмите Control-C в окне терминала.

Обратите внимание, что каждый вызов, сделанный в этом примере, является асинхронным и неблокирующим. Функции обратного вызова вызываются в ответ на события. createServerОбратный вызов обрабатывает событие запроса клиента и возвращает ответ. listenОбратный вызов обрабатывает listeningсобытие.

Библиотека Node.js

Как вы можете видеть в левой части рисунка ниже, Node.js имеет большой набор функций в своей библиотеке. Модуль HTTP, который мы использовали в примере кода ранее, содержит классы клиента и сервера, как вы можете видеть в правой части рисунка. Функциональность сервера HTTPS с использованием TLS или SSL находится в отдельном модуле.

Одна неотъемлемая проблема однопоточного цикла событий - отсутствие вертикального масштабирования, поскольку поток цикла событий будет использовать только одно ядро ​​ЦП. Между тем современные микросхемы ЦП часто имеют восемь и более ядер, а современные серверные стойки часто имеют несколько микросхем ЦП. Однопоточное приложение не сможет полностью использовать все преимущества более чем 24 ядер в надежной серверной стойке.

Вы можете это исправить, хотя для этого потребуется дополнительное программирование. Начнем с того, что Node.js может порождать дочерние процессы и поддерживать каналы между родительским и дочерним процессами, аналогично тому, как popen(3)работает системный вызов, используя child_process.spawn() и связанные методы.

Модуль кластера даже более интересен, чем модуль дочернего процесса для создания масштабируемых серверов. В cluster.fork()методе размножается рабочими процессы , которые совместно используют порты сервера родителя, используя child_process.spawn()под крышки. Мастер кластера распределяет входящие соединения между своими рабочими, используя по умолчанию алгоритм циклического перебора, который чувствителен к загрузке рабочих процессов.

Обратите внимание, что Node.js не предоставляет логику маршрутизации. Если вы хотите поддерживать состояние между соединениями в кластере, вам необходимо сохранить объекты сеанса и входа в систему где-нибудь, кроме рабочей ОЗУ.

Экосистема пакетов Node.js

Реестр NPM содержит более 1,2 миллиона пакетов бесплатного многоразового кода Node.js, что делает его крупнейшим реестром программного обеспечения в мире. Обратите внимание, что большинство пакетов NPM (по сути, папки или элементы реестра NPM, содержащие программу, описанную файлом package.json) содержат несколько модулей (программ, которые вы загружаете с помощью requireоператоров). Эти два термина легко спутать, но в этом контексте они имеют особое значение и не должны взаимозаменяться.

NPM может управлять пакетами, которые являются локальными зависимостями конкретного проекта, а также глобально установленными инструментами JavaScript. При использовании в качестве диспетчера зависимостей для локального проекта NPM может одной командой установить все зависимости проекта через файл package.json. При использовании для глобальных установок NPM часто требуются системные (sudo) привилегии.

Вам не нужно использовать командную строку NPM для доступа к общедоступному реестру NPM. Другие менеджеры пакетов, такие как Yarn от Facebook, предлагают альтернативные возможности на стороне клиента. Вы также можете искать и просматривать пакеты с помощью веб-сайта NPM.

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

Например, платформа Express, минимальная и гибкая среда веб-приложений Node.js, предоставляет надежный набор функций для создания одно-, многостраничных и гибридных веб-приложений. Хотя легко клонируемый репозиторий Expresscode находится по адресу //github.com/expressjs/express, а документация по Express находится по адресу //expressjs.com/, быстрый способ начать использовать Express - это установить его в уже инициализированную локальную рабочую разработку. каталог с npmкомандой, например:

$ npm install express - сохранить

Параметр —save, который фактически включен по умолчанию в NPM 5.0 и более поздних версиях, указывает диспетчеру пакетов добавить модуль Express в список зависимостей в файле package.json после установки.

Еще один быстрый способ начать использовать Express - установить исполняемый генераторexpress(1) глобально, а затем использовать его для создания приложения локально в новой рабочей папке:

$ npm install -g экспресс-генератор @ 4

$ экспресс / tmp / foo && cd / tmp / foo

После этого вы можете использовать NPM для установки всех необходимых зависимостей и запуска сервера на основе содержимого файла package.json, созданного генератором:

$ npm install

$ npm start

Трудно выделить основные моменты из миллиона с лишним пакетов в NPM, но несколько категорий выделяются. Express - самый старый и самый яркий пример фреймворков Node.js. Еще одна большая категория в репозитории NPM - это служебные программы разработки JavaScript, в том числе browserify, сборщик модулей; bower, менеджер пакетов браузера; grunt, средство выполнения задач JavaScript; и gulp, система потоковой сборки. Наконец, важной категорией для корпоративных разработчиков Node.js являются клиенты баз данных, которых более 8000, включая популярные модули, такие как redis, mongoose, firebase и pg, клиент PostgreSQL.

Подводя итог, Node.js - это кроссплатформенная среда выполнения JavaScript для серверов и приложений. Он построен на однопоточном, неблокирующем цикле событий, движке Google Chrome V8 JavaScript и низкоуровневом API ввода-вывода. Различные методы, включая кластерный модуль, позволяют приложениям Node.js масштабироваться за пределы одного ядра ЦП. Помимо своей основной функциональности, Node.js вдохновил экосистему из более чем миллиона пакетов, которые зарегистрированы и имеют версии в репозитории NPM и могут быть установлены с помощью командной строки NPM или альтернативы, такой как Yarn.