Асинхронное программирование в Node.js: события, коллбеки, promises
Неблокирующие функции
Основная «фишка» node.js, как известно, в том что большинство функций в ней неблокирующие. Что это значит для программиста?
Операции в программе отнимают разное время в зависимости от того к чему мы обращаемся. Операции с регистрами — самые быстрые, потом идут операции с кэшами первого и второго уровней (1 и 5 наносекунд соответственно), операции с RAM (~80-90 нс), операции с жёстким диском (~14 миллисекунд). Чтобы понять масштаб, можно взглянуть вот на этот gif. Огромная колонна - обращение к жёсткому диску. Если сделать zoom in, сверху будут видны операции с памятью и кэшами. Обращение к сетевому серверу ещё дольше — когда придёт ответ, вообще непонятно.
Философия неблокирующего ввода-вывода состоит в том что функции вообще не должны ждать окончания длительных операций ввода-вывода (диск и сеть). Для этого функция либо принимает функцию, которую надо выполнить по завершении операции (callback), либо возвращает объект-эмиттер, на который опять же вешаются функции. Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // Оставление callback'а server.query('Query text', function(data) { // Сделать что нибудь с данными }); // Оставление event-эмиттера var query_status = server.query('Query text'); query_status.addListener('success', function(data){ // Сделать что нибудь с данными }); query_status.addListener('error', function(error){ // Если пришла ошибка, тоже что нибудь сделать }); |
Оперируем двоичными данными в Node.js. Часть 1: отправка данных
Итак, со времени написания предыдущей статьи я лучше разобрался с механизмом использования двоичных данных в Node.js. Механизм этот не то чтобы очевидный, но он есть, и он работает. Как я уже упоминал, оперирование двоичными данными критически важно для использования двоичных протоколов.
Этой статьи могло не быть без кода коннектора Postgres <=> Node.js, написанного товарищем creationix. Спасибо ему за отличные исходники, в которых вполне реально разобраться без обращения непосредственно к автору
Итак, предыдущий способ (с использованием PHP.js) потерпел неудачу. В Google-группе nodejs мне посоветовали взглянуть на коннектор Postgres: это как раз реализация бинарного протокола для Node.js. После нескольких часов хакинга стало понятно, как работает обмен двоичными данными в Node. Итак, всё по порядку:
Оперируем двоичными данными в Node.js. Часть 2: получение ответа
В предыдущей статье мы собрали и отправили серверу запрос, и получили двоичную строку в ответ. Самое время эту строку препарировать ![]()
Разбираем ответ сервера
Структура ответа в Sphinx довольно проста, и понятна даже из кода PHP-коннектора (собственно, так я его и портировал). Сначала 8 байт заголовка: статус-код (int16), версия (int16), длина оставшейся части заголовка (int32). Последнее нам нужно разве что для проверки, т.к. tcp-модуль node всё равно забирает ответ Sphinx целиком и отдаёт его в callback уже склеенным.
Горячая замена кода в Node.js
Решил сегодня попробовать в Node.js горячую замену кода. В самом деле, раз скрипт крутится на сервере на манер FastCGI, логично было бы не перезапускать Node при каждой правке, а подгружать код из файла и прямо на работающем сервере менять старый callback на новый. Да и для экспериментов удобнее.
Добавляем в исходники фреймворка nerve функцию замены кода (swap()):