Выпуск серверной JavaScript-платформы Node.js 0.12
Спустя почти два года с момента появления прошлой стабильной ветки представлен значительный релиз платформы для выполнения высокопроизводительных сетевых приложений на языке JavaScript - Node.js 0.12. Затягивание разработки ветки 0.12 и излишний контроль над проектом со стороны компании Joyent привёл к расколу в стане разработчиков и основанию форка io.js. Первый выпуск io.js 1.0 во многом идентичен Node.js 0.12 и отличается использованием более свежей версией JavaScript-движка V8 и организационными изменениями, такими как переход к более короткому циклу подготовки релизов и более интенсивному продвижению новшеств. Node.js является более консервативным проектом, в котором приоритетным является обеспечение стабильности кодовой базы.
Наиболее заметные новшества, добавленные в Node.js 0.12:
Переход на версию JavaScript-движка V8 3.26, выпущенную в августе 2014 г. (в Node.js 0.10 использовался V8 3.14, выпущенный в 2012 году, а в io.js - V8 3.31.71, выпущенный в конце декабря 2014 г.).
Модуль Streams 3 с улучшенной реализацией потоков при сохранении обратной совместимости на уровне API. Из улучшений в Streams можно отметить поддержку механизмов cork и uncork для предотвращения сброса буферов при выполнении операций пакетной записи порции данных. Пакетный режим обеспечивается за счёт логического объединения в очередь передаваемых на запись данных с их последующей единовременной отправкой через системные вызовы write() и writev();
В модуле HTTP снято ограничение на число одновременно создаваемых сетевых сокетов (раньше значение maxSockets было равно 5, а теперь не ограничивается и упирается в лимиты, выставленные на стороне операционной системы). Реализована корректная поддержка KeepAlive, что позволяет держать сокеты отрытыми до истечения таймаута или закрытия соединения на другом конце. Добавлена поддержка явного сброса заголовков (flushHeaders), что позволяет исключить передачу дополнительных данных перед отправкой первого байта контента и поддержать проксированные соединения открытыми;
В модуле Cluster реализован и задействован новый режим балансировки запросов, работающий с использованием метода кругового перебора (Round Robin) при котором основной сервер принимает соединения и равномерно распределяет их среди обработчиков. Опциональная возможность использования старого метода, при котором приём соединений осуществлялся на стороне обработчиков, сохранена;
Модуль TLS переведён на новый механизм TLSWrap, который упрощает обращение из JavaScript к коду TLS на C++. Добавлены новые API для асинхронных callback-вызовов SNI, сшивания OCSP и обработки событий от хранилища;
В модуле Buffer задействован механизм более точного выделения памяти для буферов, который позволяет снизить накладные расходы при выделении множества мелких буферов, как с позиции потребления памяти, так и с точки зрения нагрузки на CPU (сборщик мусора выполняется быстрее). Добавлены новые методы, такие как buf.writeUIntLE, Buffer.compare() и buffer.equals(), представлен конструктор "new Buffer(otherBuffer)".
В средства управления дочерними процессами (child_process) добавлена поддержка вызовов spawnSync/execSync для запуска дочерних процессов в синхронном режиме (до завершения дочернего процесса работа основного потока будет приостановлена);
В модуль Crypto добавлен API для загрузки собственных движков шифрования, для их использования в OpenSSL. Обеспечена возможность шифрования ключей паролем и расширен API для получения паролей. Добавлен API для шифрования по открытым ключам RSA;
Модуль VM теперь является надстройкой над модулем Contextify, который используется для обеспечения доступа к данным из sandbox-окружения;
Начальная поддержка ECMAScript Internationalization API 1.0 (ECMA-402), которая пока доступна только для английского языка.
Платформа Node.js может быть использована как для серверного сопровождения работы Web-приложений, так и для создания обычных клиентских и серверных сетевых программ. Для расширения функциональности приложений для Node.js подготовлена большая коллекция модулей, в которой можно найти модули с реализацией серверов и клиентов HTTP, SMTP, XMPP, DNS, FTP, IMAP, POP3, модули для интеграции с различными web-фреймворками, обработчики WebSocket и Ajax, коннекторы к СУБД (MySQL, PostgreSQL, SQLite, MongoDB), шаблонизаторы, CSS-движки, реализации криптоалгоритмов и систем авторизации (OAuth), XML-парсеры.
Для обеспечения обработки большого числа параллельных запросов Node.js задействует асинхронную модель запуска кода, основанную на обработке событий в неблокирующем режиме и определении callback-обработчиков. В качестве способов мультиплексирования соединений поддерживаются такие методы, как epoll, kqueue, /dev/poll и select. Для мультиплексирования соединений используется библиотека libuv, которая является надстройкой над libev в системах Unix и над IOCP в Windows. Для создания пула потоков (thread pool) задействована библиотека libeio, для выполнения DNS-запросов в неблокирующем режиме интегрирован c-ares. Все системные вызовы, вызывающие блокирование, выполняются внутри пула потоков и затем, как и обработчики сигналов, передают результат своей работы обратно через неименованный канал (pipe). Выполнение JavaScript-кода обеспечивается через задействование разработанного компанией Google движка V8.
По своей сути Node.js похож на фреймворки Perl AnyEvent, Ruby Event Machine, Python Twisted и реализацию событий в Tcl, но цикл обработки событий (event loop) в Node.js скрыт от разработчика и напоминает обработку событий в web-приложении, работающем в браузере. При написании приложений для node.js необходимо учитывать специфику событийно-ориентированного программирования, например, вместо выполнения "var result = db.query("select..");" с ожиданием завершения работы и последующей обработкой результатов, в Node.js использует принцип асинхронного выполнения, т.е. код трансформируется в "db.query("select..", function (result) {обработка результата});", при котором управление мгновенно перейдёт к дальнейшему коду, а результат запроса будет обработан по мере поступления данных. Ни одна функция в Node.js не должна напрямую выполнять операции ввода/вывода - для получения данных с диска, от другого процесса или из сети требуется установка callback-обработчика.