V8 движок javascript для чего нужен
Использование V8
V8 — это движок JavaScript от Google, который используется в браузере Chrome. Он быстрый и доступен в исходных кодах (С++) для Linux (точнее для gcc) и под Windows.
В свете роста популярности использования V8 я решил поделиться своим (годичным) опытом его использования на платформе Windows в качестве серверного скриптового движка.
Часть 1. Введение и простейшая программа, использующая V8.
— Установка, сборка и добавление в свой проект
Итак, V8 — быстрый движок JavaScript (ECMA-262) от Google, используемый в браузере Chrome:
V8 доступен в исходных кодах по лицензии BSD:
Я расскажу как его собрать под MS Visual Studio Express Edition 2008. Установка под Windows описана здесь:
Затем добавляем в PATH пути к бинарникам python, scons и subversion.
Скачиваем текущие исходники V8 из ветки trunk (стабильной):
svn checkout v8.googlecode.com/svn/trunk v8
В папке tools\visual studio находятся проекты V8 для Visual Studio.
В них удобно изучать код, но собирать V8 лучше из командной строки (из корневой папки где SConstruct), например, так:
scons msvcltcg=off mode=release library=static snapshot=on env=»INCLUDE:C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include;C:\Program Files\Microsoft Visual Studio 9.0\VC\include,LIB:C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib;C:\Program Files\Microsoft Visual Studio 9.0\VC\lib»
(пути к установке по умолчанию MS VS EE 2008).
msvcltcg это Link Time Optimization. Рекомендуется включать только для финальных релизов, иначе размер v8.lib увеличиться в 3-4 раза и скорость линковки вашего проекта упадет.
Как видно собираем мы статическую библиотеку v8.lib, которая скоро и появится в этой же папке.
Берем v8.h из папки include и v8.lib и добавляем к своему MS Visual Studio 2008 проекту.
Также не забудьте сделать в проекте:
#pragma comment(lib, «ws2_32.lib»)
#pragma comment(lib, «winmm.lib»)
Иначе будут проблемы при линковке. Собственно, теперь движок V8 у нас доступен в проекте и можно начинать изучать Embedder’s Guide
— Введение в использование V8
Открываем v8.h и изучаем.
V8 предоставляет свою функциональность с помощью C++ классов, которые объявлены в пространстве имен (namespace) v8. Все важные javascript-структуры обернуты с помощью соответствующего С++ класса. Например, класс v8::Integer представляет собой целое число (i64) в JavaScript.
.
class Context;
class String;
class Value;
class Utils;
class Number;
class Object;
class Array;
class Int32;
class Uint32;
class External;
class Primitive;
class Boolean;
class Integer;
class Function;
class Date;
.
Самый важный класс — это контекст (v8::Context), то есть место, внутри которого компилируется и выполняется javascript-код. Фактически это же и место хранения глобального объекта javascript. Трудно представить взаимодействие с v8, которое не потребует контекста (но, наверное, можно).
Внутри себя V8 поддерживает свой собственный стек, где размещаются стековые объекты V8. Например, для использования контекста необходимо «войти в него». Для этого используется специальный класс C++ Context::Scope (подробнее ниже). Конструктор этого класса размещает на вершине стека V8 стековый объект V8 для входа в контекст. Вызов деструктора класса Context::Scope убирает соответствующий стековый объект с вершины стека V8. На стеке V8 размещаются также конструкции отлова исключений (TryCatch), пулы хранения временных хэндлов (HandleScope) и другие объекты V8. Все классы C++, которые управляют этими объектами, устроены одинаковы: в конструкторе размещаем объект на стек V8, в деструкторе — убираем.
V8 (как и любая javascript среда выполнения) содержит сборщик мусора, занимающийся удалением объектов V8, на которые никто не ссылается. Поэтому взаимодействие с объектами V8 из C++ кода происходит посредством хэндлов (v8::Handle), то бишь указателей на указатели. Упрощенно это можно представить так:
Реализованы хэндлы в виде template-классов C++: v8::Handle, v8::Local, v8::Persistent.
По времени жизни хэндлы делятся на временные (v8::Local) и постоянные (v8::Persistent).
Можно считать, что это аналоги C++ стековых и хиповых объектов, то есть время жизни временных хендлов привязано к стеку, а постоянные живут пока их явно не уничтожишь.
Далее я предполагаю, что мы находимся в пространстве имен v8 и STL («using namespace v8; using namespace std; „).
Итак, временные хэндлы V8 (v8::Local). Используются чаще всего. Сравним их время жизни со стековым объектом C++:
V8 C++
< <
HandleScope handle_scope;
Local a = Integer::New(1); int a = 1;
> >
// a нельзя использовать
Как видно, для хранения временных хендлов V8 понадобился объект HandleScope. Это стековый объект V8 для хранения тех самых ссылок на объекты V8. Упрощенно это аналог начала блока стековых переменных. Создание нового временного хендла всегда приводит к созданию ссылки в объекте HandleScope, который ближе всего к вершине стека (стека V8, разумеется). Нельзя создать временный хендл без HandleScope!
Вы будете использовать временные хендлы очень часто. Например, нам требуется преобразовать строку C++ в строку V8. Для строки в формате UTF-8 это делается следующим образом:
Многие классы (например, Integer, String, Boolean, Date) предоставляют статический метод New (возвращающий временный хэндл), который позволяет создать новый объект V8 этого класса и занести в него данные из C++. Например (см. v8.h):
Однако, может возвращаться и объект типа Value:
Класс Value хранит произвольный тип V8. Это то, на что может указывать переменная javascript: число, строка, объект, функция, массив и пр. Value предоставляет методы для проверки своего типа (IsUndefined(), IsNull(), IsString(),IsFunction() и пр.). Преобразование Value в нужный тип осуществляется с помощью метода Cast интересующего нас класса. Например:
В то же время Value является базовым классом C++ для классов Integer, String и пр. Поэтому можно делать так:
— Постоянные хэндлы V8
Есть несколько случаев, когда временные хэндлы не могут быть использованы. Иногда нам нужно самим управлять временем жизни объектов V8.
Первый случай: контекст V8. Контекст мы создаем сами и уничтожаем, когда он больше не нужен.
Второй случай: объект V8 использует экземпляр объекта C++ и содержит внутри себя ссылку на этот экземпляр. Ясно, что если сборщик мусора вдруг решит подчистить объект V8, то мы потеряем ссылку на объект C++ и произойдет утечка памяти. Однако, мы хотим, чтобы объекты V8 уничтожались! Нам просто необходимо уведомление о том, что это сейчас произойдет.
Все это возможно с помощью постоянных хэндлов V8 (Persistent).
Я приведу опять код для V8 и аналог (в смысле времени жизни) кода на C++.
Persistent p; int *p = 0;
< <
HandleScope handle_scope;
Local a = Integer::New(1); int a = 1;
p = Persistent ::New(a); p = new int (a);
> >
Persistent q = p; int * q = p;
p.Dispose(); delete p;
p.Clear(); p = 0;
Итак, основной способ получения постоянного хэндла (из временного) — это использование вызова Persistent::New(). Context является единственным классом, который при своем создании (New) сразу возвращает постоянный хэндл. Надеюсь, всем уже понятно — почему он так делает.
Вопрос получения уведомлений при уничтожении постоянных хэндлов мы отложим, а пока попробуем соорудить первую рабочую программу, которая выполняет javascript.
Для этого нам потребуется извлекать строки из объекта String V8 в C++ код. Мы воспользуемся простейшим способом — классом String::AsciiValue.
Функция, которая выполняет произвольный javascript-код, будет выглядеть так:
string v8_exec( const char * javascript)
<
HandleScope handle_scope; // стековый объект для хранения временных хэндлов
Persistent context = Context::New(); // создаем контекст и сохраняем его постоянный хэндл
Context::Scope context_scope(context); // стековый объект «входа» в контекст; для компиляции и выполнения внутри контекста
TryCatch try_catch; // стековый объект для отлова javascript-исключений
Local String > source = String ::New(javascript); // преобразуем строку с кодом в строку V8
Local
Как работает JS: о внутреннем устройстве V8 и оптимизации кода
Перед вами — второй материал из серии, посвящённой особенностям работы JavaScript на примере движка V8. В первом шла речь о механизмах времени выполнения V8 и о стеке вызовов. Сегодня мы углубимся в особенности V8, благодаря которым исходный код на JS превращается в исполняемую программу, и поделимся советами по оптимизации кода.
О JS-движках
JavaScript-движок — это программа, или, другими словами, интерпретатор, выполняющий код, написанный на JavaScript. Движок может быть реализован с использованием различных подходов: в виде обычного интерпретатора, в виде динамического компилятора (или JIT-компилятора), который, перед выполнением программы, преобразует исходный код на JS в байт-код некоего формата.
Вот список популярных реализаций JavaScript-движков.
Почему был создан движок V8?
Движок с открытым кодом V8 был создан компанией Google, он написан на C++. Движок используется в браузере Google Chrome. Кроме того, что отличает V8 от других движков, он применяется в популярной серверной среде Node.js.
Логотип V8
При проектировании V8 разработчики задались целью улучшить производительность JavaScript в браузерах. Для того, чтобы добиться высокой скорости выполнения программ, V8 транслирует JS-код в более эффективный машинный код, не используя интерпретатор. Движок компилирует JavaScript-код в машинные инструкции в ходе исполнения программы, реализуя механизм динамической компиляции, как и многие современные JavaScript-движки, например, SpiderMonkey и Rhino (Mozilla). Основное различие заключается в том, что V8 не использует при исполнении JS-программ байт-код или любой промежуточный код.
О двух компиляторах, которые использовались в V8
Внутреннее устройство V8 изменилось с выходом версии 5.9, которая появилась совсем недавно. До этого же он использовал два компилятора:
После того, как код какое-то время поработает, поток профилировщика соберёт достаточно данных для того, чтобы система могла понять, какие методы нужно оптимизировать.
Далее, в другом потоке, начинается оптимизация с помощью Crankshaft. Он преобразует абстрактное синтаксическое дерево JavaScript в высокоуровневое представление, использующее модель единственного статического присваивания (static single-assignment, SSA). Это представление называется Hydrogen. Затем Crankshaft пытается оптимизировать граф потока управления Hydrogen. Большинство оптимизаций выполняется на этом уровне.
Встраивание кода
Первая оптимизация программы заключается в заблаговременном встраивании в места вызовов как можно большего объёма кода. Встраивание кода — это процесс замены команды вызова функции (строки, где вызывается функция) на её тело. Этот простой шаг позволяет сделать следующие оптимизации более результативными.
Вызов функции заменяется на её тело
Скрытые классы
JavaScript — это язык, основанный на прототипах: здесь нет классов. Объекты здесь создаются с использованием процесса клонирования. Кроме того, JS — это динамический язык программирования, это значит, что, после создания экземпляра объекта, к нему можно добавлять новые свойства и удалять из него существующие.
Большинство JS-интерпретаторов используют структуры, напоминающие словари (основанные на использовании хэш-функций), для хранения сведений о месте расположения значений свойств объектов в памяти. Использование подобных структур делает извлечение значений свойств в JavaScript более сложной задачей, чем в нединамических языках, таких, как Java и C#. В Java, например, все свойства объекта определяются не изменяющейся после компиляции программы схемой объекта, их нельзя динамически добавлять или удалять (надо отметить, что в C# есть динамический тип, но тут мы можем не обращать на это внимание). Как результат, значения свойств (или указатели на эти свойства) могут быть сохранены, с фиксированным смещением, в виде непрерывного буфера в памяти. Шаг смещения можно легко определить, основываясь на типе свойства, в то время как в JavaScript это невозможно, так как тип свойства может меняться в процессе выполнения программы.
Так как использование словарей для выяснения адресов свойств объекта в памяти очень неэффективно, V8 использует вместо этого другой метод: скрытые классы. Скрытые классы похожи на обычные классы в типичном объектно-ориентированном языке программирования, вроде Java, за исключением того, что создаются они во время выполнения программы. Посмотрим, как всё это работает, на следующем примере:
Пока, ещё до выполнения конструктора, у объекта Point нет свойств, поэтому класс C0 пуст.
Каждый раз, когда к объекту добавляется новое свойство, в старый скрытый класс добавляются сведения о переходе к новому скрытому классу. Переходы между скрытыми классами важны, так как они позволяют объектам, которые создаются одинаково, иметь одни и те же скрытые классы. Если два объекта имеют общий скрытый класс и к ним добавляется одно и то же свойство, переходы обеспечат то, что оба объекта получат одинаковый новый скрытый класс и весь оптимизированный код, который идёт вместе с ним.
Переход к использованию класса C2 после добавления к объекту свойства y
Переходы между скрытыми классами зависят от порядка, в котором к объекту добавляются свойства. Взгляните на этот пример кода:
Встроенные кэши
V8 использует и другую технику для оптимизации выполнения динамически типизированных языков, называемую встроенным кэшем вызовов. Встроенное кэширование основано на наблюдении, которое заключается в том, что повторяющиеся обращения к одному и тому же методу имеют тенденцию происходить с использованием объектов одного типа. Более подробно об этом можно почитать здесь. Если у вас нет времени слишком в это углубляться, читая вышеупомянутый материал, здесь мы изложим концепцию встроенного кэширования буквально в двух словах.
Итак, как же всё это работает? V8 поддерживает кэш типов объектов, которые мы передали в качестве параметра недавно вызванным методам, и использует эту информацию для того, чтобы сделать предположение о типах объектов, которые будут переданы как параметры в будущем. Если V8 смог сделать правильное предположение о типе объекта, который будет передан методу, он может пропустить процесс выяснения того, как получать доступ к свойствам объекта, а, вместо этого, использовать сохранённую информацию из предыдущих обращений к скрытому классу объекта.
Встроенное кэширование вызовов, кроме того, является причиной того, почему так важно, чтобы объекты одного и того же типа использовали общие скрытые классы. Если вы создаёте два объекта одинакового типа, но с разными скрытыми классами (как сделано в примере выше), V8 не сможет использовать встроенное кэширование, так как, даже хотя объекты имеют один и тот же тип, в соответствующих им скрытых классах назначено разное смещение их свойствам.
Перед нами объекты одного типа, но их свойства a и b были созданы в разном порядке и имеют разное смещение
Компиляция в машинный код
Как только граф Hydrogen оптимизирован, Crankshaft переводит его в низкоуровневое представление, которое называется Lithium. Большинство реализаций Lithium зависимо от архитектуры системы. На этом уровне, например, происходит выделение регистров.
В итоге Lithium-представление компилируется в машинный код. Затем происходит то, что называется замещением в стеке (on-stack replacement, OSR). Перед компиляцией и оптимизацией методов, в которых программа тратит много времени, нужно будет поработать с их неоптимизированными вариантами. Затем, не прерывая работу, V8 трансформирует контекст (стек, регистры) таким образом, чтобы можно было переключиться на оптимизированную версию кода. Это очень сложная задача, учитывая то, что помимо других оптимизаций, V8 изначально выполняет встраивание кода. V8 — не единственный движок, способный это сделать.
Как быть, если оптимизация оказалась неудачной? От этого есть защита — так называемая деоптимизация. Она направлена на обратную трансформацию, возвращающую систему к использованию неоптимизированного кода в том случае, если предположения, сделанные движком и положенные в основу оптимизации, больше не соответствуют действительности.
Сборка мусора
Для сборки мусора V8 использует традиционный генеалогический подход «пометь и выброси» (mark-and-sweep) для маркировки и очистки предыдущих поколений кода. Фаза маркировки предполагает остановку выполнения JavaScript. Для того, чтобы контролировать нагрузку на систему, создаваемую сборщиком мусора и сделать выполнение кода более стабильным, V8 использует инкрементный алгоритм маркирования: вместо того, чтобы обходить всю кучу, он пытается пометить всё, что сможет, обходя лишь часть кучи. Затем нормальное выполнение кода возобновляется. Следующий проход сборщика мусора по куче начинается там, где закончился предыдущий. Это позволяет добиться очень коротких пауз в ходе обычного выполнения кода. Как уже было сказано, фазой очистки памяти занимаются отдельные потоки.
Ignition и TurboFan
С выходом в этом году V8 версии 5.9. был представлен и новый конвейер выполнения кода. Этот конвейер позволяет достичь ещё большего улучшения производительности и значительной экономии памяти, причём, не в тестах, а в реальных JavaScript-приложениях.
Новая система построена на базе интерпретатора Ingnition и новейшего оптимизирующего компилятора TurboFan. Подробности об этих новых механизмах V8 можно почитать в этом материале.
С выходом V8 5.9 full-codegen и Crankshaft (технологии, которые использовались в V8 с 2010-го года) больше применяться не будут. Команда V8 развивает новые средства, стараясь не отстать от новых возможностей JavaScript и внедрить оптимизации, необходимые для поддержки этих возможностей. Переход на новые технологии и отказ от поддержки старых механизмов означает развитие V8 в сторону более простой и хорошо управляемой архитектуры.
Улучшения в тестах производительности для браузерного и серверного вариантов использования JS
Эти улучшения — лишь начало. Новый конвейер выполнения кода на основе Ignition и TurboFan открывает путь к дальнейшим оптимизациям, которые улучшат производительность JavaScript и сделают V8 экономичнее.
Мы рассмотрели некоторые особенности V8, а теперь приведём несколько советов по оптимизации кода. На самом деле, кстати, всё это вполне можно вывести из того, о чём мы говорили выше.
Подходы к оптимизации JavaScript-кода для V8
Итоги
Мы, в SessionStack, стараемся следовать вышеизложенным принципам при написании JS-кода. Надеемся, немного разобравшись в том, как работают внутренние механизмы V8, и учтя то, что мы рассказали выше, вы сможете улучшить качество и производительность ваших программ.
Уважаемые читатели! Какими советами по оптимизации JS-кода можете поделиться вы?
Руководство по Node.js, часть 2: JavaScript, V8, некоторые приёмы разработки
Публикуя первую часть перевода этого руководства по Node.js, мы решили узнать мнение аудитории о том, стоит ли нам продолжать работу над проектом, и провели небольшой опрос. Как оказалось, нашу инициативу поддержали примерно 94% проголосовавших. Поэтому встречайте вторую часть руководства по Node.js.
Сегодня мы поговорим о том, какими знаниями в области JS нужно обладать для того, чтобы продуктивно разрабатывать приложения для платформы Node.js, обсудим различия браузерного и серверного JavaScript-кода, поговорим о JS-движках и о некоторых приёмах Node.js-разработки.
Какими JS-знаниями нужно обладать для Node.js-разработки?
Предположим, вы только начали заниматься программированием. Насколько глубоко вам нужно изучить JavaScript для успешного освоения Node.js? Начинающему трудно достичь такого уровня, когда он приобретёт достаточную уверенность в своих профессиональных навыках. К тому же, изучая программирование, вы можете почувствовать, что не понимаете точно, где заканчивается браузерный JavaScript и начинается разработка для Node.js.
Если вы находитесь в самом начале пути JavaScript-программиста, я посоветовал бы вам, прежде чем писать для Node.js, хорошо освоить следующие концепции языка:
Выше мы говорили о том, что начинающих может беспокоить вопрос о том, где проходит граница между серверной и клиентской разработкой на JavaScript. Поговорим об этом.
Различия между платформой Node.js и браузером
Чем JS-разработка для Node.js отличается от браузерного программирования? Сходство между этими средами заключается в том, что и там и там используется один и тот же язык. Но разработка приложений, рассчитанных на выполнение в браузере, очень сильно отличается от разработки серверных приложений. Несмотря на использование одного и того же языка, существуют некоторые ключевые различия, которые и превращают два эти вида разработки в совершенно разные занятия.
Надо отметить, что если тот, кто раньше занимался фронтендом, начинает изучать Node.js, у него имеется весьма серьёзная возможность довольно быстро освоить всё что нужно благодаря тому, что писать он будет на уже знакомом ему языке. Если к необходимости освоить новую среду добавляется ещё и необходимость изучить новый язык, задача значительно усложняется.
Итак главное различие между клиентом и сервером заключается в окружении, для которого приходится программировать, в экосистемах этих сред.
В браузере, в свою очередь, нет тех программных механизмов, которые имеются в среде Node.js и существуют в виде модулей, которые можно подключать к приложению. Например, это API для доступа к файловой системе.
Ещё одно различие между клиентской и серверной разработкой на JS заключается в том, что при работе в среде Node.js разработчик полностью контролирует окружение. Если только вы не занимаетесь разработкой опенсорсного приложения, которое может быть запущено где угодно, вы точно знаете, например, на какой версии Node.js будет работать ваш проект. Это очень удобно в сравнении с клиентским окружением, где вашему коду приходится работать в имеющемся у пользователя браузере. Кроме того, это означает, что вы можете, не опасаясь проблем, пользоваться новейшими возможностями языка.
Так как JavaScript крайне быстро развивается, браузеры просто не успевают достаточно оперативно реализовать все его новшества. К тому же, далеко не все пользователи работают на самых свежих версиях браузеров. В результате разработчики, которые хотят использовать в своих программах что-то новое, вынуждены это учитывать, заботиться о совместимости их приложений с используемыми браузерами, что может вылиться в необходимость отказа от современных возможностей JavaScript. Можно, конечно, для преобразования кода в формат, совместимый со стандартом EcmaScript 5, который поддерживают все браузеры, воспользоваться транспилятором Babel, но при работе с Node.js вам это не понадобится.
V8 и другие JavaScript-движки
V8 — это название JavaScript-движка, используемого в браузере Google Chrome. Именно он отвечает за выполнение JavaScript-кода, который попадает в браузер при работе в интернете. V8 предоставляет среду выполнения для JavaScript. DOM и другие API веб-платформы предоставляются браузером.
JS-движок независим от браузера, в котором он работает. Именно этот факт сделал возможным появление и развитие платформы Node.js. V8 был выбран в качестве движка для Node.js в 2009 году. В результате прямо-таки взрывного роста популярности Node.js V8 оказался движком, который в наши дни отвечает за выполнение огромного количества серверного JS-кода.
Экосистема Node.js огромна. Благодаря этому V8 также используется, посредством проектов наподобие Electron, при разработке настольных приложений.
Надо отметить, что, помимо V8, существуют и другие движки:
Эти движки реализуют спецификацию ECMA-262, называемую ещё ECMAScript. Именно эта спецификация стандартизирует JavaScript. Свежую версию стандарта можно найти здесь.
▍Разработка JS-движков и стремление к производительности
Движок V8 написан на C++, его постоянно улучшают. Он может выполняться на многих системах, в частности, на Mac, Windows и Linux. Здесь мы не будем говорить о деталях реализации V8. Сведения о них можно найти в других публикациях, в том числе — на официальном сайте V8. Они со временем меняются, иногда — очень серьёзно.
V8 постоянно развивается, то же самое можно сказать и о других движках. Это приводит, в частности, к росту производительности веб-браузеров и платформы Node.js. Производители движков для браузеров постоянно соревнуются, борясь за скорость выполнения кода, продолжается это уже многие годы. Всё это идёт на пользу пользователям и программистам.
▍Интерпретация и компиляция
JavaScript считается интерпретируемым языком, но современные движки занимаются далеко не только интерпретацией JS-кода. Они его компилируют. Это веяние можно наблюдать с 2009-го года, когда компилятор JavaScript был добавлен в Firefox 3.5, после чего и другие производители движков и браузеров переняли эту идею.
V8 выполняет компиляцию JavaScript для повышения производительности кода. Со времени появления Google Maps в 2004-м году JavaScript эволюционировал, превратился из языка, на котором, для реализации интерактивных возможностей веб-приложений, обычно писали по несколько десятков строк, в язык, на котором пишут браузерные приложения, состоящие из тысяч или даже сотен тысяч строк кода. Такие приложения могут выполняться в браузере часами, что серьёзно отличается от старых сценариев использования JS, код на котором, например, мог применяться лишь для проверки правильности данных, вводимых в формы. В современных условиях компиляция кода имеет огромный смысл, так как, хотя выполнение этого шага может отложить момент запуска кода, после компиляции код оказывается гораздо более производительным, чем тот, который обрабатывался бы исключительно интерпретатором и запускался бы быстрее, но работал бы медленнее.
Теперь, обсудив некоторые положения, касающиеся JS-движков, интерпретации и компиляции кода, перейдём к практике. А именно, поговорим о том, как завершать работу Node.js-приложений.
Выход из Node.js-приложения
Существует несколько способов завершения работы Node.js-приложений.
Модуль ядра process предоставляет удобный метод, который позволяет осуществить программный выход из Node.js-приложения. Выглядит это так:
Если вас такое положение дел устраивает — можете этим методом пользоваться. При его вызове можно передать ему целое число, которое будет воспринято операционной системой как код выхода из программы.
По умолчанию этот код имеет значение 0, что означает успешное завершение работы. Другие коды выхода имеют другие значения, которые могут оказаться полезными для использования их в собственной системе для того, чтобы наладить взаимодействие одних программ с другими.
Подробности о кодах завершения работы программ можно почитать здесь.
После того, как программа завершит работу, Node.js вернёт системе этот код.
Надо отметить, что работа программы самостоятельно завершится естественным образом после того, как она выполнит все заданные в ней действия. Однако в случае с Node.js часто встречаются программы, которые, в идеальных условиях, рассчитаны на работу неопределённой длительности. Речь идёт, например, об HTTP-серверах, подобных такому:
Для завершения работы подобных программ нужно воспользоваться сигналом SIGTERM и выполнить необходимые действия с помощью соответствующего обработчика.
Рассмотрим следующий пример:
Что такое «сигналы»? Сигналы — это средства взаимодействия процессов в стандарте POSIX (Portable Operating System Interface). Они представляют собой уведомления, отправляемые процессу для того, чтобы сообщить ему о неких событиях.
Отправить такой сигнал можно и из самой программы, воспользовавшись следующей командой:
Для успешного выполнения подобной команды нужно знать PID процесса, который планируется завершить.
Чтение переменных окружения из Node.js
Подобным образом можно работать и с другими переменными среды, например, с теми, которые установлены вами самостоятельно.
Итоги
Сегодня мы коснулись вопросов браузерного и серверного программирования на JavaScript, поговорили о JS-движках, о том, как завершать работу серверных приложений, и о том, как читать переменные среды из Node.js-программ. В следующий раз мы расскажем о хостингах для Node.js-приложений, о том, как пользоваться Node.js в режиме REPL, о работе с аргументами, которые можно передавать скриптам при их вызове, о взаимодействии с консолью, и об оформлении кода в виде модулей.
Уважаемые читатели! Какие учебные материалы по JavaScript вы посоветовали бы начинающим?