Глава 1.7 Библиотеки движка

Оглавление

Глава 1.7   Библиотеки движка

1.7.1    Петля событий

1.7.2   Ввод / Вывод

1.7.3   libuv

1.7.4   DNS

1.7.5   Crypto

1.7.6   Zlib

1.7.7.   HTTP парсер

Глава 1.8   Заключение

Глава 1.7 Библиотеки движка

Сам по себе движок JavaScript еще не создает платформу. Чтобы Node.js мог выполнять свои задачи, такие как обработка событий, ввод-вывод или поддержка дополнительных функций, например DNS(разрешение доменных имен)или шифрование – требуется дополнительная функциональность. Это выполняется за счет использования дополнительных библиотек. Для многих задач, которые приходится выполнять платформе Node.js, уже существуют готовые решения. По этому причине, Дайль решил построить платформу Node.js на основе набора внешних библиотек, а те пробелы, которые не были кем то должным образом реализованы, заполнить своими реализациями. Преимущество данной стратегии заключается в том, что нет необходимости заново изобретать велосипед и возможностью использовать проверенные библиотеки.

Ярким примером использования данной стратегии является ОС Unix. В этом контексте, разработчики должны следовать следующему принципу: сосредоточиться только на актуальной проблему и решить ее максимально качественно, а для всего остального использовать доступные библиотеки. Большинство программ из командной оболочки UNIX реализуют ту же философию. Если программное решение хорошо себя зарекомендовало, оно может быть использовано для решения похожих проблем. Это решение дает преимущество в том, что удобный алгоритм необходимо разработать всего один раз, а работать оно будет во многих программных продуктах.  Тоже самое относится и к исправлению ошибок. Если появится ошибка в разрешении доменных имен, необходимо исправить ошибку всего один раз, а уже то решение будет работать во всех программах, где используют эту библиотеку. Но это решение содержит и обратную сторону медали – библиотеки, которые использует платформа, должны существовать в той ОС, где запускается платформа Node.js. Node.js решает эту проблему за счет использования небольшого количества библиотек, которые должна предоставить ОС. Эти зависимости от библиотек скорее состоят из базовых функций, таких как GNU CC( С компилятор GNU) или стандартная С библиотека. Остальные зависимости, такие как zlib или http_parser – включены в исходный код.

1.7.1    Петля событий

Клиентская часть JavaScript содержит много элементов архитектуры управления событиями. Большинство пользовательских  взаимодействий вызывает события, на которые отвечают соответствующие вызовы функций.  Используя различные возможности, такие как функции первого класса и анонимные функции в JavaScript, Вы можете реализовывать целые приложения, построенные на архитектуре использования управляемых событии. Термин “управляемые события” означает, что объекты не взаимодействуют друг с другом напрямую через вызовы функций; вместо этого для связи используются события. Поэтому управляемое событиями программирование в основном используется для управления потока программы. В отличие от классического подхода, когда исходный код прогоняется линейно, здесь функции выполняются при наступлении событий. Небольшой пример в Листинге 1.2 демонстрирует этот подход.

myObj.on('myEvent', (data) => {
    console.log(data);
});
myObj.emit('myEvent', 'Hello World');

Листинг 1.2 Разработка управлением событий в Node.js

Вы можете использовать метод on объекта, производного от events.EventEmitte, компонента платформы Node.js, чтобы определить какую функцию вы хотите использовать при наступлении того или иного события. Этот шаблон называется – публикация – подписка. Таким образом можно регистрировать объекты в генераторе событий, а затем получать уведомления при наступлении событий. Первый аргумент метода on– это имя события в виде строки, которое необходимо обработать. Второй аргумент – это функция обратного вызова, которая выполняется при наступлении этого события. Таким образом вызов функции onне делает ничего, кроме регистрации функции обратного вызова. Позже в скрипте вызывается метод emit для объекта myObj. Это гарантирует выполнение функций обратного вызова, которые зарегистрированы методом on.

Код выполнения функции обратного вызова, приведенный в этом примере, выполняется платформой  Node.js асинхронно. Однако сами функции обратного вызова выполняются последовательно, а не параллельно. Однопоточный подход в Node.js создает весомую проблему – в один момент времени может выполняться только одна задача. Как отсюда следует – длительные операции чтения и записи должны блокировать выполнение приложения. По этой причине все операции чтения и записи передаются внешним модулям платформы(в данном случае ОС) с использованием петли обработки событий(Прим. переводчика – в русскоязычном сегменте обычно Вы встретите наименование – цикл обработки событий, вместо слова петля. Я не считаю этот перевод правильным). Это позволяет коду приложения использовать доступный поток, не заблокированный длительными операциями. Как только в приложении происходит запрос к внешнему ресурсу – он передается в петлю обработки событий. Для этого запроса регистрируется обратный вызов, который перенаправляет запрос ОС; затем Node.js возвращает контроль и продолжает выполнение приложения. Когда внешняя операция будет завершена, результат будет передан обратно в петлю событий. Цикл обрабатывает событие и вызывает соответствующий событию зарегистрированный метод обратного вызова. На рисунке 1-4 показано, как работает петля обработки событий.

Event Loop
Рисунок 1-4 Петля событий

Петля событий, используемая в Node.js, базируется на библиотеке libev, написанной на языке C, которая отличается высокой производительностью и большим набором функций. Библиотека libev основана на библиотеке libevent, но имеет более высокую производительность, что подтверждается различными тестами. Даже вторая версия libevent2 не дотягивает по производительности до библиотеки libev. Из соображений кроссплатформенной совместимости петля обработки событий в Node.js была абстрагирована для обеспечения лучшей переносимости.

1.7.2 Ввод / Вывод

Петля событий сама по себе в сочетании с движком V8 может помочь в решении большого количества задач, но у нас по прежнему нет возможности взаимодействия с операционной системой в плане чтения и записи файлов в файловой системе. При разработке серверных приложений, доступ к файловой системе играет очень важное значение. Например конфигурация приложения хранится обычно в отдельном конфигурационном файле. Далее эта конфигурация должна быть как то прочитана приложением. Также и шаблоны, которые динамически заполняются значениями и затем отправляются клиентам, также хранятся в отдельных файлах. Чтение и запись информации с файлов – это важное требование к серверным приложениям. Также не забывайте про возможность логирования своей работы приложением – в этой операции также используются I/O операции для записи в журнал различных сообщений – ошибки, предупреждения или даже информация о времени выполнения той или иной операции. Доступ к записи также используется для сохранения важной информации. Иногда во время работы приложения, пользователем создается/передается некая информация, которая должна быть восстановлена при последующей работе пользователя.

Node.js использует для задач I/O библиотеку libeio, написанную на языке C. Эта реализация позволяет выполнять операции чтения и записи асинхронно, и поэтому библиотека libeio тесно интегрирована с петлей событий. Однако на этом возможности библиотеки libeio не ограничиваются – она предлагает широкий набор возможностей для взаимодействия с файловой системой. Эти возможности варьируются от чтения информации из файла(права доступа, размер и дата создания) до управления директориями(например создание или удаление) и до модификации прав доступа. Также как и петля событий – в процессе разработки модуль I/O был отделен от приложения уровнем абстракции.

Для доступа к файловой системе, Node.js предоставляет собственный системный файловый модуль. Этот модуль позволяет взаимодействовать с  интерфейсами библиотеки libeio и таким образом представляет из себя оболочку над libeo.

1.7.3 libuv

Две библиотеки, которые мы уже рассмотрели – относятся к Linux библиотекам. Однако при разработке Node.js была цель сделать мультиплатформенную разработку. По этой причине в версии 0.6 платформы Node.js была добавлена библиотека libuv. Эта библиотека призвана абстрагировать различия между различными операционными системами. Именно поэтому использование libuv позволяет платформе Node.js работать в ОС семейства Windows. До версии 0.6, ядро движка V8 работало с   библиотеками libeio и libev напрямую. После выхода версии 0.6 эти 2 библиотеки не интегрируются в платформу напрямую, а абстрагируются.

Чтобы Node.js работал в ОС Windows – необходимо предоставить основные компоненты для платформы Windows. Проблем с V8 здесь не возникает – он прекрасно работает уже много лет в браузере Google Chrome в Windows без каких бы то не было проблем. Однако с петлей обработки событий или с асинхронными операциями ситуация сложнее. Некоторые компоненты Libev должны быть переписаны для работы в ОС Windows. Кроме того, libev в своей работе опирается на реализацию тех или иных функций, предоставляемых ОС, но в Windows предоставлен оптимизированный вариант , доступный в виде IOCP.  В libuv были внедрены некоторые основные концепции Node.js. Например, мы больше не говорим события, мы используем термин операции. Операция передается компоненту libuv, внутри libuv уже принимается решение, куда операция дальше передается – компоненту libev  или IOCP. Таким образом, интерфейсы Node.js остается неизменным вне зависимости от используемой операционной системы.

libuv отвечает за управление всеми асинхронными операциями ввода/вывода. Это означает, что доступ ко всей файловой системе, будь то запись или чтение осуществляется через интерфейсы libuv. Для этой цели libuv предоставляет функции uv_fs_ , а также  таймеры – вызовы, зависящие от от времени и асихронные TCP и UDP соединения , выполняемые через libuv. В дополнение к этому базовому функционалу, libuv предоставляет дополнительные возможности – такие как создание и порождение дочерних процессов и планировщик очереди потоков – абстракция, которая позволяет выполнять задачи в отдельным потоках и привязывать к ним функции обратного вызова. Использование такого уровня абстракции,  делает libuv важным строительным блоком для широко внедрения платформы и делает Node.js более кроссплатформенным.

1.7.4 DNS

Платформа Node.js предназначена для работы в сети Интернет. Когда Вы захотите разместить свое приложение или сайт в глобальной сети интернет, Вы быстро столкнетесь с проблемой разрешения имен. Обращение к серверам в интернет пространстве происходит через их ip-адреса. В 4-ой версии интернет протока (IPv4), любой интернет адрес представлен 32 – битным числом, представленным 4-мя блоками по 8 бит. В интернет протоколе 6 версии(IPv6), интернет адрес имеет размер 128 бит и разделен на 8 блоков шестнадцатеричных чисел. Но никто не хочет запоминать эти сложные наборы чисел, особенно если интернет адрес назначается  динамически через протокол DHCP. Решение этой проблемы были придумано очень и очень давно и называется оно – система доменных имен(DNS). DNS – служба разрешения имен, которая преобразует доменные имена в ip-адрес. Существует также обратное преобразование имен, когда ip-адрес преобразуется в доменное имя. Если Вы хотите подключиться к веб сервису или прочитать страницу в Node.js приложении, здесь также используется DNS.

Node.js не занимается самостоятельным разрешением доменных имен, а передает запрос библиотеке C-Ares. Это справедливо для всех методов модуля DNS, кроме метода dns.lookup, который использует функцию операционной системы getaddrinfo. Это исключение вызвано тем фактом, что вызов getaddrinfo более постоянен в результатах выполнения функции, чем результат работы библиотеки C-Ares, хотя последняя и более производительна, чем вызов getaddrinfo.

1.7.5 Crypto

Криптографический компонент платформы Node.js предоставляет нам несколько вариантов шифрования. Этот компонент создан на базе протокола OpenSSL. Это означает, что пакет OpenSSL должен быть установлен на Вашей системе, если Вы хотите шифровать данные. Криптомодуль позволяет Вам шифровать данные несколькими алгоритмами, а также создавать цифровые подписи Ваших приложений. Сама система шифрования основана на приватном и публичном ключе. Приватный(закрытый) ключ, как следует из названия, предназначен только для Вашего приложения. Публичный(открытый) ключ доступен Вашим клиентам. Если сообщение должно быть зашифровано – это делается с помощью публичного ключа. А расшифрованы данные могут быть только с помощью приватного ключа. То же самое относится и к цифровой подписи данных. В этом случае Ваш закрытый ключ используется для создания цифровой подписи. Затем получатель сообщения может проверить целостность сообщения и отследить, вами было отправлено сообщение или нет, используя публичный ключ и Вашу подпись.

1.7.6 Zlib

Когда Вы создаете веб приложения, Вам как разработчику необходимо заранее подумать о доступных компьютерных ресурсах Ваших пользователей и о ресурсах Вашего собственного сервера. Например, пропускная способность сети или доступная память могут быть ограничены физически. Для этих случае платформа Node.js содержит компонент zlib. С его помощью Вы можете сжимать и распаковывать данные, когда в этом возникнет необходимость. Для сжатия данных, Вы можете использовать 2 алгоритма – Deflate и Gzip. Node.js обрабатывает сжатые данные, как потоки.

Node.js сам не занимается сжатием и распаковкой данных, вместо этого использует библиотеку zlib и передает запросы ей. Модуль zlib платформы Node.js предоставляет облегченную оболочку для алгоритмов Gzip, Deflate/Inflate и Brotli и обеспечивает обработку потоков ввода/вывода.

1.7.7 HTTP Parser

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

Главная цель разработки Node.js заключается в разработке высокопроизводительной платформы для веб приложений. Поэтому Node.js имеет модульную структуру. Это позволяет включать в платформу отлаженные, протестированные и высокопроизводительные библиотеки, такие как например описанные нами HTTP Parser или libeio. Модульный подход распространяется также на внутренние модули платформы Node.js и распространяется на расширения, которые вы создаете для своих приложений.

В этой книге Вы узнаете о различных возможностях и технологиях платформы Node.js для разработки Ваших собственных приложений. Мы начнем наше знакомство именно с модульной системы Node.js.

1.8 Заключение

Уже на протяжении многих лет Node.js является неотъемлемой частью веб разработки. Также Node.js используется не только для создания серверных приложений, но также служит инструментом для множества других задач: сборщик веб пакетов, такой как Babel или компилятор для CSS препроцессоров. Успех платформы основывается на нескольких простых концепциях. Node.js базируется на коллекции стабильных библиотек, которые создают гибкую и надежную платформу. На протяжении всего своего срока жизни, ядро остается компактным и содержит в себе набор только самых необходимых базовых функций. Для всех остальных задач и требований Вы можете использовать менеджер пакетов npm, чтобы интегрировать широкий набор компонентов в Ваше приложение

Хотя Node.js проверен временем, Вы имеете полное право задать вопрос: безопасно ли использовать Node.js для моих приложений? До версии 0.6 нельзя было ответить однозначно утвердительно на этот вопрос, поскольку в интерфейсы платформы постоянно вносили разные изменения. Однако в настоящий момент Node.js стал зрелой и стабильной платформой. Разработчики поддерживают стабильность интерфейсов. LTS версия была создана для корпоративных приложений. LTS версия поддерживается обновлениями на протяжении 30 месяцев. Это поддерживает надежность платформы и избавляет компании от необходимости выполнения постоянных обновлений.

Одной из самых захватывающих глав в истории развитии платформы было разделение на ветку разработки io.js, поскольку к тому времени разработка платформы потеряла динамику и в платформу перестали внедрять значимые улучшения. Этот момент стал критической точкой в разработке Node.js. В этот момент было создано Node.js сообщество и ответственность в разработке перешла от одного человека к техническому комитету. Как результат у платформы появились регулярные обновления, релизы, что свидетельствует о надежности и дальнейшем стабильном развитии платформы.

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

 

Leave a Reply

Please disable your adblocker or whitelist this site!