Fork me on GitHub

Руководство для начинающих по Node.js от Felix’a

В интернете сейчас много информации про Node.js, но, учитывая скорость, с которой идет разработка, достаточно тяжело найти актуальную информацию о том, с чего начать. Это руководство ставит перед собой именно такую цель - оставаться актуальным для последней стабильной версии Node.js.

Сейчас руководство соответствует последним изменениям в версии Node.js 0.4.x., которая является стабильной веткой.

Изучение JavaScript

Предполагается, что Вы уже знакомы с JavaScript. Если нет, то можно начать с чтения Eloquent JavaScript, свободно распространяемой книги от Marijn Haverbeke.

Hello World

Этот пример продемонстрирует как установить Node.js, включая создание простого http сервера.

Установка Node.js

Прежде всего, для того, чтобы использовать Node.js, необходимо иметь под рукой работающую *nix-подобную операционную систему. Рекомендуется Linux или OSX, но также могут подойти FreeBSD или cygwin (под windows). В настоящее время ведутся работы над портированием Node.js под windows, но пока они не доведены до стабильного состояния.

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

Получить последние исходные коды можно на сайте nodejs.org. Для получения и установки версии 0.4.5 необходимо выполнить следующие команды:

$ wget http://nodejs.org/dist/node-v0.4.5.tar.gz
$ tar -xzf node-v0.4.5.tar.gz
$ cd node-v0.4.5.tar.gz
$ ./configure
$ sudo make install

Node.js не имеет внешних зависимостей, кроме python, который используется при сборке. В OSX необходимо установить XCode перед началом установки. В Ubuntu же необходимо выполнить:

$ apt-get -y install build-essential

Интерактивная оболочка Node.js

Если установка прошла без ошибок, то станет доступен вызов интерактивной оболочки Node.js, например:

$ node
> console.log('Hello World');
Hello World

Интерактивная оболочка (или REPL) удобна для тестирования простых однострочных примеров. Кроме того, она может быть внедрена в любое Node.js приложение. Для того, чтобы выйти из интерактивной оболочки, необходимо просто нажать Ctrl + C.

Оболочка (REPL) обладает множеством удобств, основным среди которых является автодополнение.

Первая программа

Для того, чтобы создать приложение для Node.js, необходимо всего лишь создать новый файл с расширением ‘.js’. Например, можно создать файл ‘hello_world.js’ со следующим содержимым:

console.log('Hello World');

После того, как файл сохранен, его можно запустить на выполнение из терминала/консоли следующим образом:

$ node hello.js
Hello World

hello world http-сервер

В наше время вывод на терминал ‘hello world’ не сильно впечатляет. Необходимо идти дальше и написать программу, которая отдает ‘hello world’ по http. Для этого необходимо создать файл ‘hello_http.js’ и поместить в него следующий код:

var http = require('http');

var server = http.createServer(function(req, res) {
  res.writeHead(200);
  res.end('Hello Http');
});

server.listen(8080);

Для того, чтобы запустить это приложение, необходимо выполнить в терминале/ консоле:

$ node hello_http.js

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

Чтобы проверить работу сервера, достаточно открыть новую закладку в web-браузере и перейти по следующему адресу. Как и ожидалось, ответом будет: ‘Hello Http’.

В качестве альтернативы, можно воспользоваться терминалом/консолью и, используя curl, протестировать работу сервера:

$ curl localhost:8080
Hello Http

Теперь необходимо поближе посмотреть на код созданной программы. В первой строке подключается http модуль ядра и присваивается переменной http. О модульной системе будет рассказано более подробно в следующем разделе.

В следующей строке создается переменная server которой присваивается результат вызова метода http.createServer. Аргументом при вызове этого метода является замыкание, которое будет вызываться каждый раз, когда приходит http-запрос.

И в конце вызывается метод server.listen(8080), который указывает Node.js на каком порту требуется работа сервера. Если необходимо запустить сервер на 80-ом порту, то программу необходимо запускать с правами супер пользователя.

Далее, когда в браузере идет обращение к адресу localhost:8080, вызывается замыкание с параметрами req и res. Req - это поток, доступный для чтения, который содержит данные каждого http-запроса (например, подтверждение формы или загрузка файла). Res - это поток, доступный для записи, который используется для отправки данных обратно клиенту. В примере отсылается заголовок 200 OK, а также тело ответа ‘Hello Http’.

Модульная система

Для организации программ в виде отдельных файлов Node.js предлагает к использованию модульную систему.

Для демонстрации подхода создадим файл ‘main.js’ со следующим содержимым:

var hello = require('./hello');
hello.world();

Нетрудно догадаться, что require(‘./hello’) используется для импорта данных из отдельного JavaScript файла. ‘./’ означает, что файл находится в той же директории, что и сам файл ‘main.js’. Также следует обратить внимание на то, что не требуется указывать расширение файла, так как ‘.js’ подставляется по умолчанию.

Далее необходимо создать файл ‘hello.js’ со следующим содержимым:

exports.world = function() {
  console.log('Hello World');
}

Тут следует обратить внимание на то, что происходит присваивание свойству ‘world’ объекта ‘exports’. Таким образом объявляется, что модуль ‘hello.js’ экспортирует во вне функцию ‘world’. Объект ‘exports’ доступен в любом модуле и возвращается при каждом вызове функции require при подключении модуля. При запуске ‘main.js’ вывод будет следующим:

$ node main.js
Hello World

Будет не лишним упомянуть, что зачастую объект ‘exports’ переопределяется следующим образом:

module.exports = function() {
  // ...
}

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

Следующая вещь, которую надо понимать при работе с модульной системой, это то, как система работает с вызовами ‘require’, которые не включают относительную подсказку о местоположении подключаемого файла. Например:

var http = require('http');

Первое, что сделает Node.js - это определит, есть ли модуль ядра с именем http. Если есть, то вернет соответствующую директорию. Но что будет при работе с модулями не относящимися к ядру, как, например, ‘mysql’?

var mysql = require('mysql');

В этом случае Node.js будет искать модуль в каждой директории, начиная с одного из текущих файлов, и проверять есть ли директория с именем ‘node_modules’. Если такая директория найдена, Node.js начнет поиск в ней файла с именем ‘mysql.js’. Если подходящих файлов не найдено и достигнут корень файловой системы (‘/’), Node.js сдается и выбрасывает исключение.

В настоящий момент Node.js учитывает дополнительный изменяемый список альтернативных директорий для импорта. Список доступен через массив require.paths. Однако идет активное обсуждение на тему удаления этой возможности, так что лучше пока не использовать ее.

И наконец, Node.js учитывает файл ‘index.js’, в котором описывается главный файл импорта для директории. Таким образом, если встретится вызов require(‘./foo’), то Node.js будет пробовать искать файлы и ‘foo.js’ и ‘foo/index.js’.

Использование EventEmitters

Node.js реализует шаблон проектирования наблюдатель (рус), используя класс EventEmitter. Всегда, когда есть объект, который является источником событий, Node.js наследует класс этого объекта от класса EventEmitter.

Использовать EventEmitter и его наследников довольно просто. Необходимо лишь вызвать метод ‘on()’ у объекта, генерирующего события, и передать в качестве параметров имя события и функцию обратного вызова. Например:

var data = '';
req
  .on('data', function(chunk) {
    data += chunk;
  })
  .on('end', function() {
    console.log('POST data: %s', data);
  })

Как видно, функция on() возвращает ссылку на объект, которому она принадлежит, что позволяет связывать в цепочки вызовов несколько прослушивателей событий.

Если интересует только первое возникновение события, то вместо on() можно использовать функцию once().

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

var onData = function(chunk) {
  console.log(chunk);
  req.removeListener(onData);
}

req.on('data', onData);

Этот пример идентичен случаю использования метода once().

Что дальше?

Теперь у вас есть базовые знания о Node.js и сейчас лучше попробовать написать самостоятельно несколько небольших программ. Лучшее место для начала - это документация по API node.js.

Отладка приложений Node.js

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

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

Использование console.log()

Самый просто способ понять проблему - это исследовать объекты с помощью console.log(). Объекты можно передавать в качестве параметров:

var foo = {bar: 'foobar'};
console.log(foo);

Или же можно использовать sprintf-подобные возможности для форматирования отладочных сообщений:

var foo = {bar: 'foobar'};
console.log('Hello %s, this is my object: %j', 'World', foo);

Использование отладчика Node.js

Если console.log() чем-то не устраивает или есть вероятность, что текущая проблема может быть решена быстрее с помощью точек останова, то наиболее подходящим вариантом будет встроенный Node.js отладчик. Отладчик вызывается легко:

$ node debug my_file.js

План

Дописать раздел

Использование WebKit Inspector

План

Дописать раздел

Фреймворки

Новичку с Node.js вряд ли захочется изобретать колесо, когда потребуется разобрать POST-запрос, маршрутизировать URL или сформировать представление. В этих случаях с большой долей вероятности захочется использовать один из популярных веб-фреймворков. Данный раздел дает беглый обзор основных из них и мое отношение к ним.

Express

На текущий момент express - наиболее подходящий фреймворк для большинства Node.js-разработчиков. Он относительно зрелый и построен на базе connect. Поддерживает такие возможности, как маршрутизация, конфигурация, шаблонный движок, разбор POST запросов и многое другое.

В то время, как express уже достаточно цельный фреймворк, он используется в гораздо меньших масштабах по сравнению с такими аналогами, как Rails, CakePHP или Django. Express наболее сопоставим с таким инструментом, как Sinatra и, к сожалению, пока не сделал больших усилий для того, чтобы уйти от Ruby корней в сторону чего-то более естественного для JavaScript. Так или иначе, его использование гораздо проще и быстрее, чем создание своего собственного фреймворка и в настоящий момент это наиболее достойный выбор.

fab.js

Думаете, что знаете JavaScript? Подумайте еще раз. Разработчики fab.js, вдохновленные цепочками jQuery, выбрали очень необычный подход. Каждая функция возвращает функцию, устраняя необходмиость в именах методов вообще. Тем самым формируется код, напоминающий Lisp.

На данный момент я не считаю, что fab.js готов к промышленной разработке. Но если вы все еще изучаете мир Node.js, то вам абсолютно необходимо попробовать в работе эту библиотеку как минимум один раз. Если альтернативы нет, то fab.js откроет мир, в котором JavaScript не копирует решения Ruby, Python или PHP при создании веб-фреймворков и может развиваться уникальным образом.

Хостинг и Deployment

Быстрый Deployment

Если вы написали первое приложение для Node.js, то наверняка хотите запустить его как можно быстрее. Вот как это можно сделать:

1. Скопируйте программу на сервер, где приложение будет запущено. Если используется git, то это просто означает, что необходимо сделать клон репозитория из стороннего сервера или сервиса (например GitHub).

2. Предполагая, что проект содержит файл ‘server.js’, необходимо перейти в директорию, в которой содержится этот файл и выполнить:

$ screen
$ node server.js

Этот пример запускает ‘server.js’ внутри screen-сессии. Screen - это утилита, предоставляющая возможность сохранять состояние shell’a даже в случае, если закрыт терминал/консоль, через который происходило соединение с сервером.

Таким образом, теперь можно безопасно закрыть терминал/консоль (из screen выходить через control-a + d), а ‘server.js’ при этом продолжит работать в screen-сессии. Если есть необходимость проверить работу приложения, можно снова соединиться с сервером и выполнить:

$ screen -r

Эта команда восстановит соединение с shell’ом, в котором в фоне работает ‘server.js’.

Однако, этот подход рекомендуется только для экспериментального deployment’a. Так как, если в приложении произойдет сбой, screen не попытается перезапустить его. Соответственно, для production окружения этот метод котегорически не рекомендуется.

Joyent no.de

План

Дописать раздел