Node.js Handbook полезные ссылки и туториалы


Оглавление (нажмите, чтобы открыть):

Форум

Справочник

Поиск по форуму
Расширенный поиск
К странице.

Учебник Javascript

Добро пожаловать в учебник javascript.

Вас, наверно, заинтересует его более новый вариант: http://learn.javascript.ru.

Этот учебник создан, преимущественно, для обучения современному javascript-программированию с нуля. Отдельные разделы, возможно, будут интересны и «продвинутому» читателю.

  1. Существует новый учебник http://learn.javascript.ru. Он более новый и полный, чем тот, что здесь.
  2. Еще в этом году открылись Курсы JavaScript онлайн.

читать дальше »

Здесь мы разберем основы javascript, включая синтаксис и первые примеры.

Кроме того, подберем инструменты для редактирования и разработки.

Этот раздел особенно рекомендуется тем, кто только начинает изучать javascript. читать дальше »

Большинство действий в javascript выполняется с HTML-страницей. В javascript страница представлена в виде объектной модели DOM (Document Object Model).

Любые действия со страницей требуют вызова соответствующего метода DOM.

Понимание, как работать с документом в модели DOM — краеугольный камень в javascript-программировании. читать дальше »

Основная ценность javascript — в его интеграции со страницей. Любой документ или DOM-элемент умеет инициировать различные события, а на событие, зная его имя, можно назначить обработчик. читать дальше »

Описание объектов в Javascript, наследования и особенностей. читать дальше »

Раздел по AJAX объединен. Смотрите раздел Учебник по AJAX и COMET. читать дальше »

Регулярные выражения в javascript немного странные. Вроде — перловые, обычные, но с подводными камнями, на которые натыкаются даже опытные javascript-разработчики.

Эта статья ставит целью перечислить неожиданные фишки и особенности RegExp в краткой и понятной форме.

Общую информацию о регулярных выражениях в javascript вы можете найти в статье Регулярные выражения. читать дальше »

а почему ветка «Базовые типы, функции, конструкции языка» не включена в «Учебник Javascript», а стоит особняком?

Потому что это именно учебник.

Есть различные форматы материала: справочник, статья, учебник.
У них разные цели, отсюда и различия в подаче информации.

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

довольно ясное объяснение,хотелось бы книгу скачать!

Есть и получше конечно. Хотелось бы подробнее.

Подборка книг по JavaScript для начинающих

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

JavaScript сейчас доминирует в мире IT. С его помощью вы можете как создать маленькое веб-приложение, так и запрограммировать робота. К счастью, язык существует уже довольно давно, и овладевшие им в превосходстве разработчики описали свой опыт программирования на нём в книгах.

Eloquent JavaScript (Выразительный JavaScript)

Эта книга рассказывает, как заставить компьютеры делать то, что вам от них нужно. Компьютеры сегодня так же распространены, как отвёртки — но содержат гораздо больше скрытых сложностей, и поэтому их сложнее понять и с ними сложнее работать. Для многих они остаются чуждыми, слегка угрожающими штуками. Также книга доступна на русском языке.

JavaScript Enlightenment

В этой книге дан тщательный обзор мира JavaScript через разбор встроенных объектов и нюансов языка. Эта книга точно не предназначена для людей, только начинающих изучать программирование вообще и JavaScript в частности.

Learning JavaScript Design Patterns

Эта книга посвящена рассмотрению как классических, так и современных шаблонов программирования на JavaScript. В целом ориентирована на начинающих программистов.

JavaScript Tutorial

HTML5 даёт великолепные возможности. Как и jQuery. Как и Node.JS. Если добавить к ним ещё немного чистого JavaScript — вы запросто покорите веб.

Human JavaScript

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

Speaking JavaScript

Эта книга даст вам универсальные знания о JavaScript, понимание как его общей логики, так и деталей. Автор предполагает, что читатель уже знаком с принципами объектно-ориентированного программирования и каким-либо языком вроде PHP, Ruby, Python, C++ или Java.

Изучаем программирование на JavaScript

Вы готовы сделать шаг вперед в своей практике веб-программирования и перейти от верстки в HTML и CSS к созданию полноценных динамических страниц? Тогда пришло время познакомиться с самым «горячим» языком программирования — JavaScript!

Прочитав эту книгу, вы узнаете все о языке JavaScript: от переменных до циклов. Вы поймете, почему разные браузеры по-разному реагируют на код и как написать универсальный код, поддерживаемый всеми браузерами. Вы поймете, почему JS — это будущее, и станете настоящим фронтенд-разработчиком.

Building Front-End Web Apps with Plain JavaScript

В этой книге показано, как писать на JS фронтенд приложений, не используя никаких третьесторонних фреймворков или библиотек.

Programming JavaScript Applications

Кроме общего знания принципов JavaScript, эта книга подарит вам также знания из смежных областей, вроде JSON или NoSQL, а так же понимание того, как вообще пишутся веб-приложения.

Single page apps in depth

Как понятно из названия, эта книга посвящена разработке одностраничных приложений. В ней нет описания конкретных технологий и фреймворков, но зато неплохо описаны общие шаблоны и практики.

DOM Enlightenment

Книга посвящена работе с DOM (Document Object Model) — пожалуй, самому важному в JavaScript для всех веб-разработчиков.

JavaScript: The Good Parts (JavaScript: сильные стороны)

Эта книга, написанная Дугласом Крокфордом, создателем JSON и JSLint, является классикой мира JavaScript, и прочитать её должен каждый. В ней рассказывается об основах объектно-ориентированного подхода и приводится множество примеров, как хороших, так и плохих. Разумеется, автор рассказывает, как исправлять такие «вредные» примеры и как не допускать подобных ошибок.

Серия книг «You Don’t Know JS»

Эта серия, написанная известным преподавателем Кайлом Симпсоном, состоит из 6 книг, каждая из которых покрывает отдельный раздел языка. Главным преимуществом этих книг является то, что они достаточно короткие, благодаря чему вы не успеете отвлечься. А книгу «ES6 и не только» из этой серии вы можете приобрести в бумажном варианте на русском языке.

JavaScript и jQuery. Исчерпывающее руководство

JavaScript — это главный инструмент веб-разработчиков, позволяющий делать интернет-страницы интерактивными, динамичными и достичь наивысшей производительности. Это отлично структурированное руководство по JavaScript, которое позволит быстро изучить этот не самый простой в освоении, но очень востребованный язык. Большое внимание в книге уделено библиотеке jQuery. Присутствуют также много примеров и подробно разобранных заданий.

Прочитав «Исчерпывающее руководство» вы сможете:

  • Сделать страницы своего сайта интерактивными.
  • Освоить последнюю версию плагина jQuery UI.
  • Создавать удобные формы с автоматической валидацией и исправлением данных.
  • Применять технологию AJAX.
  • Углубить свои знания в области и стать профессионалом.

Javascript и jQuery. Интерактивная веб-разработка

После изучения основ верстки вам непременно захочется большей интерактивности и красоты, а также более удобных способов взаимодействия сайта с бэкендом. Тогда-то на арену и выходит JavaScript вместе с безумно популярным фреймворком jQuery. Для начала работы с книгой от вас не требуется никаких глубоких знаний – все их вы получите именно из нее. Здесь демонстрируются только новейшие практики в области кроссбраузерности и оптимизации страниц, а изложение ведется понятным языком с наглядными примерами и иллюстрациями.

JavaScript. Подробное руководство

Книга, уже ставшая классикой. В ее последнем издании охватываются HTML5 и ECMAScript 6 – актуальнейшие на нынешний день технологии. Также в нем добавлены новые главы, посвященные jQuery и JavaScript на стороне сервера. Это руководство пригодится как совсем еще новичкам, так и тем, кто хочет отточить свое знание JavaScript до совершенства.

The Node Handbook

I wrote this book to teach you all I know about Node.js!

Download it now!

It’s 189 pages long. I last updated it in fall 2020

Available in PDF, ePub and Mobi

Here is what people say about me and my work:

I’m amazed by how @flaviocopes keeps pushing out so much quality content on such useful topics. His blog is a go-to reference for good quality tutorials on web development.

Thank you for writing such a great Vue handbook! It’s been super helpful so far and I’m only about halfway through 🙂

Really appreciate your work @flaviocopes. Vue handbook and your blog are very helpful for beginners like me.

You saved my life a couple of times with your guides ����

I’m in love with every single article on your blog��

Writes awesome, well structured JS tutorials at a crazy pace.
He owns tomorrow’s SERP about anything Javascript.
�� @flaviocopes

If you’ve been looking for a good beginner’s resource to learn Vue.js you’re in luck.

Here’s a free full-length Vue Handbook by @flaviocopes that covers Directives, Events, Watchers, and more. (1 hour read) https://t.co/q07FYtf86N

Great stuff! Because I have to learn about Vue.js for a project that I’m working too!

hey @flaviocopes , thanks for this , really great stuff!

you’re amazing man, releasing all this super cool, useful, comprehensive stuff — for FREE. Massive props to you Flavio ����

Node.js для начинающих

О проекте

Цель данного документа — помочь вам начать разработку приложений на Node.js и научить всему, что необходимо знать о «продвинутом» JavaScript. Это больше, чем обычный «Hello world»-туториал.

Статус

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

Код примеров этой книги тестировался на Node.js версии 0.8.8 (проверено по англ. версии —прим.перев.).

Целевая аудитория

Вероятно, документ будет полезен читателям с базовыми знаниями, примерно, как у меня: опыт работы хотя бы с одним объектно-ориентированным языком, таким как Ruby, Python, PHP или Java, небольшой опыт в Javascript и полный новичок в Node.js.

Документ рассчитан на разработчиков, уже знакомых с другими языками программирования. Это значит, что здесь не приводится объяснение действительно базовых вещей, таких как типы данных, переменные, управляющие структуры и т. д. Вы должные разбираться в этих понятиях, чтобы понимать эту книгу.

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

Структура учебника

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

Это, конечно, не изменит мир, но мы будем стараться и научимся писать не просто куски кода, которых «достаточно», чтобы сделать это возможным, но и создадим простой, полноценный framework для чистого разделения различных аспектов вашего приложения. Скоро вы увидите, что я имею в виду.

Мы начнём с выяснения того, чем JavaScript в Node.js отличается от JavaScript в браузере.

Далее, мы остановимся на написании традиционного «Hello world»-приложения, которое является наиболее простым примером «что-то делающего» кода Node.js.

Тогда мы обсудим, какое «реальное» приложение мы хотим создать, проанализируем компоненты, которые необходимо реализовать для написания данного приложения, и начнём работать над каждым из них, шаг за шагом.

Как и было обещано, по пути мы узнаем о некоторых продвинутых понятиях JavaScript, о том как их использовать и посмотрим, почему разумно использовать эти понятия вместо привычных нам в других языках программирования.

Исходный код законченного приложения доступен в the NodeBeginnerBook Github репозитории.

JavaScript и Node.js

JavaScript и Вы

До того как мы поговорим о технических вещах, позвольте занять некоторое время и поговорить о вас и ваших отношениях с JavaScript. Эта глава позволит вам понять, имеет ли смысл читать дальше.

Скорее всего, как и в моем случае, вы начали свой путь в веб-разработке с написания простых статических HTML-документов. Вместе с этим, вы познакомились с веселой штукой, называемой JavaScript, но использовали его исключительно в простых случаях, добавляя интерактивности на ваши веб-странички.

Что вы хотели узнать — так это действительно полезные вещи; вы хотели знать, как создать сложный сайт. Для этого вы изучали PHP, Ruby, Java и начинали писать backend-код.

Тем не менее, вы постоянно следили за JavaScript, вы видели, что с появлениям JQuery, Prototype и других фреймворков этот язык стал больше, чем просто window.open().

Однако, это всё ещё относилось к frontend-разработке. Конечно, jQuery — очень мощный инструмент, но всякий раз, когда вы приправляли ваш сайт разными jQuery-«фишками», в лучшем случае, вы были JavaScript-пользователем нежели JavaScript-разработчиком.

А потом пришел Node.js. JavaScript на сервере: насколько это хорошо?

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

В этом — как раз и проблема. JavaScript живёт двумя, может даже тремя разными жизнями: весёлый маленький DHMTL-помощник из середины 90-х годов, более серьезный frontend-инструмент в лице jQuery и наконец серверный (server-side, backend) JavaScript. По этой причине не так просто найти информацию, которая поможет вам познать правильный JavaScript, пригодный для написания Node.js приложения в манере, дающий ощущение, что вы не просто использовали JavaScript, а действительно разрабатывали на JavaScript.

Это — наиболее правильный подход. Вы — уже опытный разработчик, вы не хотите изучать новые технологии поверхностно, просто валяя дурака. Вы хотите быть уверенным, что вы подходите к проблеме под правильным углом.

Конечно, существует отличная документация по Node.js, но её зачастую недостаточно. Нужно руководство.

Моя цель заключается в обеспечении вас руководством.

Предупреждение

Существуют действительно отличные специалисты в области JavaScript. Я не из их числа.

Я — действительно, тот парень, о котором написано в предыдущем параграфе. Я знаю кое-что о разработке backend веб-приложений, но я всё ещё новичок в «реальном» JavaScript и всё ещё новичок в Node.js. Я узнал некоторые продвинутые аспекты JavaScript совсем недавно. Я неопытен.

Вот почему эта книга не из разряда «от новичка к эксперту», а скорее «от новичка к продвинутому новичку».

Если всё удастся, то этот документ станет тем руководством, которое я хотел бы иметь, когда начинал в Node.js.

Server-side JavaScript

Первая инкарнация JavaScript жила в теле браузера. Но это всего лишь контекст. Он определяет, что вы можете делать с языком, но не говорит о том, что язык сам по себе может сделать. JavaScript это «полноценный» язык: вы можете использовать его в различных контекстах и достичь всего того, что можете достичь с другими «полноценными» языками.

Node.js — действительно, просто другой контекст: он позволяет вам запускать JavaScript-код вне браузера.

Чтобы ваш JavaScript код выполнился на вычислительной машине вне браузера (на backend), он должен быть интерпретирован и, конечно же, выполнен. Именно это и делает Node.js. Для этого он использует движок V8 VM от Google — ту же самую среду исполнения для JavaScript, которую использует браузер Google Chrome.

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

Таким образом, Node.js состоит из 2 вещей: среды исполнения и полезных библиотек.

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

«Hello world»

Хорошо, давайте пойдём сразу с места в карьер и напишем наше первое Node.js-приложение: «Hello world».

Откройте ваш любимый редактор и создайте файл под названием helloworld.js. Мы хотим вывести строку «Hello world» в консоль, для этого пишем следующий код:

Сохраняем файл и выполняем его посредством Node.js:

Это должно вывести Hello World на наш терминал.

Ладно, всё это скучно, правда? Давайте напишем что-нибудь полезное.

Полномасштабное веб-приложение с Node.js

Что должно делать наше приложение

Возьмём что-нибудь попроще, но приближенное к реальности:

  • Пользователь должен иметь возможность использовать наше приложение с браузером;
  • Пользователь должен видеть страницу приветствия по адресу http://domain/start;
  • Когда запрашивается http://domain/upload, пользователь должен иметь возможность загрузить картинку со своего компьютера и просмотреть её в своем браузере.

Вполне достаточно. Конечно, вы могли бы достичь этой цели, немного погуглив и поговнокодив. Но это не то, что нам нужно.

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

Задачи

Давайте проанализируем наше приложение. Что нужно, чтобы его реализовать:

  • У нас — онлайн веб-приложение, поэтому нам нужен HTTP-сервер;
  • Нашему серверу необходимо обслуживать различные запросы в зависимости от URL, по которому был сделан запрос. Для этого нам нужен какой-нибудь роутер (маршрутизатор), чтобы иметь возможность направлять запросы определенным обработчикам;
  • Для выполнения запросов, пришедших на сервер и направляемые роутером, нам нужны действующие обработчики запросов;
  • Роутер, вероятно, должен иметь дело с разными входящими POST-данными и передавать их обработчикам запросов в удобной форме. Для этого нам нужен какой-нибудь обработчик входных данных;
  • Мы хотим не только обрабатывать запросы, но и показывать пользователю контент по запрошенным URL-адресам, поэтому нам нужна некая логика отображения для обработчиков запросов, чтобы иметь возможность отправлять контент пользовательскому браузеру;
  • Последнее, но не менее важное — пользователь сможет загружать картинки, поэтому нам нужен какой-нибудь обработчик загрузки, который возьмёт на себя заботу о деталях.

Давайте подумаем о том, как бы мы реализовали это на PHP. Скорее всего, типичное решение будет на HTTP-сервере Apache с установленным mod_php5.
Это относится к первому пункту наших задач, то есть, «принимать HTTP-запросы и отправлять готовые веб-странички пользователю» — вещи, которые PHP сам не делает.

С Node.js — немного иначе. Потому что в Node.js мы не только создаем наше приложение, мы также реализуем полноценный HTTP-сервер. Действительно, наше веб-приложение и веб-сервер — в сущности, одно и тоже.

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

Давайте просто начнём реализовывать нашу первую задачу — HTTP-сервер.

Реализация приложения

Простой HTTP-сервер

Когда я подошел к моменту создания своего первого «реального» Node.js-приложения, я задался вопросом, как организовать мой код.
Я должен делать всё в одном файле? Большинство учебных пособий в интернете учат как создавать простой HTTP-сервер в Node.js, сохраняя всю логику в одном месте. Что, если я хочу быть уверенным, что мой код останется читабельным по мере реализации всё большего функционала.

На самом деле, достаточно легко отыскивать проблемные участки вашего кода, который разделён на модули.

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

Так, давайте создадим главный файл, который мы будем использовать для запуска нашего приложения, и файл модуля, в котором будет находиться наш HTTP-сервер.

Я думаю, это более-менее традиционно назвать главным файлом index.js. А код нашего сервера имеет смысл поместить в файл под названием server.js.

Давайте начнём с модуля сервера. Создайте файл server.js в корневой директории вашего проекта и поместите туда следующий код:

И всё! Вы написали работающий HTTP-сервер. Давайте проверим его, запустив и протестировав. Во-первых, выполните ваш скрипт в Node.js:

Теперь откройте ваш браузер и перейдите по адресу http://localhost:8888/. Должна вывестись веб-страница со строкой «Hello world».

Правда, это довольно интересно? Как насчёт того, чтобы поговорить о том, что здесь происходит и оставить на потом вопрос о том, как организовать наш проект? Я обещаю, мы вернемся к нему.

Анализ нашего HTTP-сервера

Хорошо, тогда давайте проанализируем, что здесь действительно происходит.

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

Далее, мы вызываем одну из функций http-модуля createServer. Эта функция возвращает объект, имеющий метод listen, принимающий числовое значение порта нашего HTTP-сервера, который необходимо прослушивать.

Пожалуйста, проигнорируйте функцию, которая определяется внутри скобок http.createServer.

Мы могли бы написать код, который запускает наш сервер, прослушивающий порт 8888, так:

Это запустило бы HTTP-сервер прослушивающего порт 8888, который больше ничего не делает (даже не отвечает на входящие запросы).

Действительно интересная (и, если вы привыкли к более консервативным языкам как PHP, довольно странная) часть — это определение функции там, где вы бы ожидали увидеть первый параметр для createServer().

Оказывается, эта определяемая функции и есть первый (и только) параметр, который мы передаём в createServer() при вызове. Потому что в JavaScript функции могут быть переданы как параметр в другую функцию.

Передача функций в качестве параметра

Вы можете в качестве примера сделать что-то подобное:

Разберите пример внимательно! Здесь мы передаём функцию say как первый параметр функции execute. Не значение, которое возвращает функция say, а саму функцию say!

Таким образом, say становится локальной переменной someFunction внутри execute и execute может вызвать функцию в этой переменной вот так: someFunction() (то есть, добавив скобки).

Конечно же, так как say принимает один параметр (word), execute может передать какое-либо значение в качестве этого параметра, когда вызывает someFunction.

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

Мы определяем функцию, которую хотим передать в execute, прямо там, где у execute должен быть первый параметр.

Из-за того, что нам даже не надо давать имя этой функции, её называют анонимная функция.

Это первый проблеск, который я называю «продвинутый» JavaScript, но давайте всё по порядку. А сейчас давайте просто примем то, что в JavaScript мы можем передать функцию как параметр, когда вызываем другую функцию. Мы можем сделать это путём присвоения нашей функции переменной, которую му передаем, или путём определения функции для передачи на месте.

Как анонимная функция делает наш HTTP-сервер рабочим

С этими знаниями давайте вернемся назад к нашему минималистичному HTTP-серверу:

Сейчас должно быть ясно, что мы здесь делаем: передаём в функцию createServer анонимную функцию.

Мы можем добиться того же самого через рефакторинг нашего кода:

Может сейчас самое время спросить: Почему мы это делаем так?

Событийно-ориентированные обратные вызовы

Ответ на вопрос a) не так легко дать (по крайней мере для меня), и b) кроется в самой природе работы Node.js — это событийно-ориентированность, то, благодаря чему он работает так быстро.

Возможно, вы захотите занять немного своего времени и почитать отличный пост Felix Geisendörfer Понимание node.js, чтобы прояснить этот момент.

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

Когда вызываем метод http.createServer, мы, конечно, не только хотим иметь сервер, слушающий какой-то порт. Мы также хотим что-нибудь сделать, когда приходит HTTP-запрос на этот сервер.

Проблема состоит в асинхронности: запрос происходит в любой момент времени, в то время как у нас только один процесс, в котором запущен наш сервер.

Когда пишем PHP-приложения, мы не беспокоимся обо всем этом: всякий раз, когда приходит HTTP-запрос, веб-сервер (обычно Apache) ответвляет новый процесс специально для этого запроса и запускает соответствующий PHP-скрипт с нуля, который выполняется от начала до конца.

Когда приходит новый запрос на порт 8888, относительно потоков управления, мы находимся в середине нашей Node.js-программы. Как это понять, чтоб не помешаться?

Это как раз то, где событийно-ориентированный дизайн Node.js/JavaScript на самом деле помогает. Нам надо узнать некоторые новые понятия, чтобы досконально понять всё это.

Мы создаем сервер и передаём функцию в созданный им метод. Всякий раз, когда наш сервер получает запрос, переданная нами функция будет вызываться.

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

Этот принцип называется обратный вызов или callback. Мы передаём в некоторый метод функцию и этот метод исполняет её, когда происходит связанное с методом событие.

По крайней мере для меня, это заняло некоторое время, чтобы понять. Просто почитайте блог Felix Geisendörfer снова, если вы всё ещё не уверены.

Давайте немного поиграем с этим новым понятием. Можем ли мы доказать, что наш код продолжает работать после создания сервера, даже если нет HTTP-запроса и callback-функция, переданная нами, не вызывается? Давайте попробуем:

Обратите внимание, что я использую console.log для вывода текста «Request received.», когда срабатывает функция onRequest (наш callback), а текст «Server has started.» — сразу после запуска HTTP-сервера.

Когда мы запустим этот код (как обычно, node server.js), он тут же выведет в командной строке «Server has started.». Всякий раз, когда мы делаем запрос нашему серверу (через переход по адресу http://localhost:8888/ в нашем браузере), в командной строке выводится сообщение «Request received.».

Объектно-ориентированный асинхронный серверный JavaScript с callback-ми в действии 🙂

(Обратите внимание, что наш сервер, возможно, будет выводить «Request received.» в консоль 2 раза при открытии страницы в браузере. Это происходит из-за того, что большинство браузеров будут пытаться загрузить фавикон по адресу http://localhost:8888/favicon.ico при запросе http://localhost:8888/)

Как наш сервер обрабатывает запросы

Хорошо, давайте быстро проанализируем остальной код сервера внутри тела нашей callback-функции onRequest().

Когда callback запускается и наша функция onRequest() срабатывает, в неё передаются 2 параметра: request и response.

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


И наш код делает именно это: Всякий раз, когда запрос получен, он использует функцию response.writeHead() для отправки HTTP-статуса 200 и Content-Type в заголовке HTTP-ответа, а функцию Response.Write() для отправки текста «Hello World» в теле HTTP-ответа.

И последнее, мы вызываем response.end() чтобы завершить наш ответ.

На данный момент, мы не заботимся о деталях запроса, поэтому мы не используем объект request полностью.

Выбор места для нашего серверного модуля

Я обещал, что мы вернёмся к организации нашего приложения. У нас есть код очень простого HTTP-сервера в файле server.js и я упоминал, что общепринято иметь главный файл с названием index.js, который используется для начальной загрузки и запуска нашего приложения, путём использования других модулей приложения (таких как наш модуль HTTP-сервера в server.js).

Мастер Йода рекомендует:  Как сделать баннер для сайта

Давайте поговорим о том, как сделать server.js настоящим Node.js-модулем, чтобы его можно было использовать в нашем главном файле index.js.

Как вы могли заметить, мы уже использовали модули в нашем коде:

Где-то внутри Node.js живёт модуль под названием «http» и мы можем использовать его в нашем коде, путём подключения и присвоения его результата локальной переменной.

Это делает нашу локальную переменную объектом, содержащим в себе все публичные методы модуля http.

Общепринитая практика — использовать имя модуля для имени локальной переменной, но мы свободны в своём выборе делать, как нам нравится:

Теперь понятно, как использовать внутренние модули Node.js. А как создать свой собственный модуль и как его использовать?

Давайте выясним это, превратив наш скрипт server.js в настоящий модуль.

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

Сейчас функционал нашего HTTP-сервера надо экспортировать, что довольно просто: скрипты, подключающие наш модуль сервера, просто запускают сервер.

Чтобы сделать это возможным, поместим код нашего сервера в функцию под названием start и будем экспортировать эту функцию:

Теперь мы можем создать наш основной файл index.js, и запускать наш HTTP-сервер там, хотя код для сервера находится всё ещё в файле server.js.

Создаём файл index.js со следующим содержимым:

Как вы могли видеть, мы можем использовать модуль сервера просто как внешний модуль: вызвав этот файл и определив для него переменную, экспортированные функции становятся доступны нам.

Вот и всё. Сейчас мы можем запустить наше приложение через главный скрипт и он будет делать всё то же самое, что и раньше:

Великолепно — сейчас мы можем помещать различные части нашего приложения в разные файлы и связывать их вместе, посредством превращения их в модули.

До сих пор мы работали только с первой частью нашего приложения: получение HTTP-запроса. Но нам надо что-нибудь с ним делать. В зависимости от URL, запрошенного браузером у нашего сервера, мы должны реагировать по-разному.

В очень простом приложении мы могли бы делать это напрямую внутри callback-функции onRequest(). Но, как я говорил, давайте добавим немного больше абстракции, чтобы сделать наш пример интереснее.

Задание соответствия между разными HTTP-запросами и разными частями нашего кода называется «маршрутизация» («routing», роутинг). Давайте тогда создадим модуль под названием router.

Что необходимо для «роутера»?

Нам нужно иметь возможность скармливать запрошенный URL и возможные добавочные GET- и POST-параметры нашему роутеру и, с учётом этого, роутер должен определять, какой код выполнять (этот код есть третья составляющая нашего приложения: коллекция обработчиков запросов, делающие необходимую работу по определённому запросу).

Итак, нам надо рассматривать HTTP-запрос и извлекать запрошенный URL, а также GET/POST-параметры. Можно поспорить, должен ли этот код быть частью роутера или сервера (или даже своего собственного модуля), но давайте сейчас пока просто сделаем его частью сервера.

Вся необходимая нам информация доступна через объект request, который передается в качестве первого параметра нашей callback-функции onRequest(). Чтобы интерпретировать эту информацию, нам необходимо добавить кое-какие Node.js-модули, а именно url и querystring.

Модуль url поддерживает методы, которые позволяют нам извлекать различные части URL (такие как запрошенный путь (URL path) и строка параметров запроса (query string)), а querystring в свою очередь, используется для парсинга строки параметров запроса (query string):

Конечно, мы также можем использовать querystring для парсинга тела POST-запроса, как мы увидим далее.

Давайте сейчас добавим в нашу функцию onRequest() логику, необходимую для извлечения пути URL (pathname), запрошенного браузером:

Замечательно. Теперь наше приложение может различать запросы на основе запрошенного пути URL. Это позволяет нам направлять запросы нашим обработчикам запросов в зависимости от пути URL, используя наш роутер. Таким образом, мы можем строить наше приложение RESTful-путём, потому что теперь можем реализовать интерфейс, следующий принципам Идентификации ресурсов (смотри статью в википедии REST для справки).

В контексте нашего приложения, это означает, что мы сможем обрабатывать запросы с URL /start и /upload разными частями нашего кода. Скоро мы увидим, как всё соединяется вместе.

Теперь самое время написать наш роутер. Создаём новый файл под названием router.js со следующим содержимым:

Конечно этот код ничего не делает, но сейчас этого достаточно. Давайте сначала посмотрим, как скрепить этот роутер с нашим сервером до того как поместим больше логики в роутер.

Нашему HTTP-серверу необходимо знать о роутере и использовать его. Мы могли бы жёстко прописать эти зависимости в нашем сервере, но, так как мы знаем только сложные способы из нашего опыта в других языках программирования, мы сделаем слабосвязанную зависимость сервера и роутера через внедрение этих зависимостей (можете почитать отличный пост Мартина Фаулера по внедрениям зависимости на английском языке или статью в Википедии на русском языке для дополнительной информации).

Для начала, расширим нашу серверную функцию start(), чтобы дать нам возможность передавать функцию route() как параметр:

Теперь расширим наш index.js соответственно, то есть внедрим функцию route() нашего роутера в сервер:

Мы опять передаём функцию, которая не является чем-то новым для нас.

Если мы сейчас запустим наше приложение (node index.js, как обычно) и запросим какой-нибудь URL, вы сможете увидеть в консоли, что наш HTTP-сервер использует наш роутер и передает ему запрошенный pathname:

(Я опустил слегка надоедливый вывод для запроса /favicon.ico)

Исполнение королевских постановлений в царстве глаголов

Позвольте мне ещё раз побродить вокруг и около и снова поговорить о функциональном программировании.

Передача функций связана не только с техническими соображениями. Относительно разработки программного обеспечения это — почти философия. Просто подумайте: в нашем index-файле мы могли бы передавать объект router в наш сервер и сервер мог бы вызывать функцию route этого объекта.

Этим способом мы бы передавали нечто и сервер использовал бы это нечто, чтобы сделать что-то. Эй, роутер, не могли бы вы показать мне маршрут?

Но серверу не нужно нечто. Ему нужно только получить что-то сделанное, а чтоб получить уже что-то сделанное, вам не нужно нечто совсем, вам необходимо действие. Вам не нужно существительное, вам нужен глагол.

Понимание фундаментальных умозаключений, которые лежат в основе этой идеи, позволило мне действительно понять функциональное программирование.

Я понял это, когда читал шедевр Стива Йегге Execution in the Kingdom of Nouns (частичный перевод на русский Исполнение королевских постановлений в царстве существительных). Почитайте это обязательно. Это одно из лучших произведений о программировании, которое я когда-либо имел удовольствие встречать.

Роутинг реальных обработчиков запроса

Вернёмся к делу. Наш HTTP-сервер и наш роутер запросов сейчас — лучшие друзья, и общаются друг с другом так, как мы хотели.

Конечно, этого недостаточно. «Роутинг» подразумевает, что мы хотим обрабатывать запросы на разные URL по-разному. Мы хотели бы иметь «бизнес-логику» для запросов к /start в одной функции, а для запросов к /upload в другой.

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

Давайте эти функции, в которые направляются запросы, назовём обработчиками запросов. И давайте возьмёмся за них сейчас, потому что делать что-либо с роутером сейчас пока не имеет смысла.

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

Это позволяет нам связать обработчики запросов с роутером, давая нашему роутеру что-нибудь маршрутизировать.

В этот момент мы должны принять решение: захардкодить использование модуля requestHandlers в роутере или мы хотим ещё немного внедрения зависимостей? Хотя внедрение зависимостей, как и любой другой паттерн, не должен использоваться только ради того, чтобы быть использованным, в нашем случае имеет смысл сделать слабосвязанную пару роутера и обработчиков запроса и, таким образом, сделать роутер действительно многоразовым.

Это означает, что нам нужно передавать обработчики запросов из нашего сервера в наш роутер, но это немного неправильно, поэтому мы должны пройти весь путь и передать их в сервер из нашего главного файла, а также — оттуда передавать в роутер.

Как мы собираемся передать их? Сейчас у нас есть два обработчика, но в реальном приложении это число будет увеличиваться и меняться. И мы уверены, что не хотим возиться с роутером каждый раз, когда добавляется новый URL + обработчик запроса. И какие-нибудь if запрос == x then вызвать обработчик y в роутере будут более чем убоги.

Переменное число элементов и каждому соответствует строка (запрашиваемый URL)? Так, похоже на ассоциативный массив, это наиболее подходящее.

Это решение немного разочаровывает тем фактом, что JavaScript не поддерживает ассоциативные массивы. Или нет? Оказывается в действительности, если нам нужны ассоциативные массивы, мы должны использовать объекты!

Об этом есть хорошее введение http://msdn.microsoft.com/en-us/magazine/cc163419.aspx. Позвольте мне процитировать подходящую часть:

В C++ или C#, когда мы говорим об объектах, мы ссылаемся на экземпляры классов или структуры. Объекты имеют разные свойства и методы, в зависимости от шаблонов (классов), экземплярами которых они являются. Но не в случае с JavaScript-объектами. В JavaScript, объекты — это просто коллекция пар имя/значение — JavaScript-объект — это как словарь со строковыми ключами.

Если JavaScript-объекты это просто коллекции пар имя/значение, как тогда у них могут быть методы? Итак, значения могут быть строками, числами и т.д. или функциями!

Хорошо, наконец-то возвращаемся к нашему коду. Мы решили, что мы хотим передать список из requestHandlers как объект и, для того, чтобы достичь слабое связывание, мы хотим внедрить этот объект в route().

Начнём с добавления объекта в наш главный файл index.js:

Хотя handle — это больше из разряда «нечто» (коллекция обработчиков запроса), я, всё-таки, предлагаю называть его глаголом, потому что в результате это будет функциональное выражение в нашем роутере, как вы скоро увидите.

Как вы можете видеть, это действительно просто — назначать различные URL соответствующему обработчику запроса: просто добавляя пару ключ/значение из «/» и requestHandlers.start, мы можем выразить красивым и аккуратным способом, что не только запросы к «/start», но также и запросы к «/» должны быть обработаны обработчиком start.

После определения объекта мы передали его в сервер как дополнительный параметр. Изменим наш server.js, чтобы использовать его:

Мы добавили параметр handle в функцию start() и передаём объект handle в callback-функцию route() в качестве перового параметра.

Соответственно, изменим функцию route() в нашем файле router.js:

Что мы здесь делаем — мы проверяем, существует ли обработчик запроса для данного пути, и если существует, просто вызываем соответствующую функцию. Из-за того, что мы имеем доступ к нашим функциям обработчиков запроса из нашего объекта просто, как если бы имели доступ к элементу ассоциативного массива, у нас есть это прекрасное выражение handle[pathname]();, о котором говорилось ранее: «Пожалуйста, handle этот pathname».

Хорошо, это всё, что нужно, чтобы связать сервер, роутер и обработчики запроса вместе! При запуске нашего приложения и запроса http://localhost:8888/start в браузере, мы можем убедиться, что надлежащий обработчик запроса действительно был вызван:

Так же открываем http://localhost:8888/ в нашем браузере и убеждаемся, что эти запросы в самом деле обрабатываются обработчиком запросов start:

Создание ответа обработчиков запроса

Замечательно. Вот только если бы обработчики запроса могли отправлять что-нибудь назад браузеру, было бы ещё лучше, правильно?

Вспомните, «Hello World», который выводит ваш браузер в запрошенной странице, всё ещё исходит от функции onRequest в нашем файле server.js.

«Обработка запроса» подразумевает «ответ на запросы» в конце концов, поэтому необходимо дать возможность нашим обработчикам запроса общаться с браузером так же, как это делает функция onRequest.

Как делать не надо

Прямой подход, который мы захотим использовать как разработчики с опытом в PHP или Ruby, на самом деле ложный: он может прекрасно работать, иметь большой смысл, а потом, когда мы этого не ждём, неожиданно всё развалится.

Под «прямым подходом» я подразумеваю использование в обработчиках запроса return «» для контента, который надо показать пользователю, и отправлять этот ответ в функцию onRequest назад пользователю.

Давайте просто сделаем это и тогда увидим, почему это не такая уж и хорошая идея.

Мы начнём с обработчиков запроса и заставим их возвращать то, что хотели бы показать в браузере. Нам надо изменить requestHandlers.js вот так:

Хорошо. Также, роутер должен вернуть серверу то, что обработчики запроса вернули ему. Поэтому надо отредактировать router.js так:

Как видим, возвращается некоторый текст «404 Not found», если запрос не может быть маршрутизирован.

И самое последнее, но не менее важное, нам нужен рефакторинг нашего сервера, чтобы заставить его отвечать браузеру с контентом обработчиков запроса, возвращаемых через роутер. Трансформируем server.js в:

Если запустим наше написаное приложение, всё будет работать замечательно: запрос http://localhost:8888/start выдаст в браузере результат «Hello Start», запрос http://localhost:8888/upload даст нам «Hello Upload», а http://localhost:8888/foo выведет «404 Not found».

OK, тогда в чём проблема? Короткий ответ: потому что мы столкнемся с проблемами, если один из обработчиков запроса захочет использовать неблокирующую операцию в будущем.

Подробный ответ займёт немного больше времени.

Блокирование и неблокирование

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

Вместо того, чтобы объяснять, что такое «блокирование» и «неблокирование», давайте продемонстрируем себе, что произойдёт, если мы добавим блокирующую операцию в наши обработчики запроса.

Для этого модифицируем обработчик запроса start так, чтобы он ждал 10 секунд до того как вернёт свою строку «Hello Start». В JavaScript нет такой штуки как sleep(), поэтому мы будем использовать хитрый хак.

Пожалуйста, измените requestHandlers.js как описано далее:

Просто объясню, что этот код делает: когда функция start() вызвана, Node.js ожидает 10 секунд и только тогда возвращает «Hello Start». Когда вызывается upload(), она выполняется немедленно, как и раньше.

(Конечно, вы уже поняли, вместо засыпания на 10 секунд, в start() могут быть реальные блокирующие операции, такие как сложные длительные вычисления.)

Давайте посмотрим, что поменялось.

Как обычно, нам надо перезапустить сервер. На этот раз я попрошу вас следовать немного более сложному «протоколу», чтобы увидеть, что произошло: во-первых, откройте браузер или таб. В первом окне браузера, введите, пожалуйста, http://localhost:8888/start в адресную строку, но не переходите пока по этому адресу!

В адресную строку второго окна браузера введите http://localhost:8888/upload и снова не переходите по адресу.

Теперь сделайте, как описано далее: нажмите клавишу Enter в первом окне («/start»), а затем быстро переключитесь на второе окно («/upload») и нажмите тоже Enter.

Что вы будете наблюдать: URL /start потребуется 10 секунд для загрузки, как мы и ожидали. Но URL /upload так же потребуется 10 секунд на загрузку, хотя в соответствующем обработчике запроса нет sleep()!

Почему? Потому что start() содержит блокирующую операцию. Like in «it’s blocking everything else from working».

И в этом проблема, потому что, как говорят: «В node всё работает параллельно, за исключением вашего кода».

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

Но для этого нам надо использовать обратные вызовы, передавая функции внутри тех функций, которые могут сделать то, что занимает некоторое время (как например sleep() на 10 секунд или запрос к базе данных или какое-то дорогостоящее вычисление.)

Таким образом, мы как бы говорим: «Эй, возможноДолгаяФункция(), пожалуйста, сделай вот это, но я, однопотоковый Node.js, не собираюсь ждать здесь, пока ты закончишь, я продолжу выполнение строчек кода ниже тебя, а ты возьми пока вот эту функцию callbackFunction() и вызови её, когда всё сделаешь. Спасибо!»

(Если хотите почитать об этом более подробно, пожалуйста посмотрите пост Mixu на Understanding the node.js event loop.)

И мы сейчас увидим, почему способ, которым мы создали «обработчик запроса обрабатывающий ответ» в нашем приложении не позволит правильно использовать неблокирующие операции.

Ещё раз давайте попробуем испытать проблему на своей шкуре, модифицировав наше приложение.

Мы снова используем наш обработчик запроса start. Пожалуйста, измените его следующим образом (файл requestHandlers.js)

Как можно видеть, мы просто внедрили новый модуль Node.js child_process. Мы сделали так, потому что это позволит нам использовать очень простую, но полезную неблокирующую операцию: exec().

Что делает exec() — она выполняет shell-команду внутри Node.js. В этом примере мы собираемся использовать её, чтобы получить список всех файлов в текущей директории («ls -lah»), позволяя нам отобразить этот список в браузере пользователя, запросившего URL /start.

Что делает этот код: создает новую переменную content (с начальным значением «empty»), выполняет «ls -lah», заполняет переменную результатом и возвращает её.

Как обычно, запустим наше приложение и посетим http://localhost:8888/start.

Которая загрузит нам красивую страничку со строкой «empty». Что тут не так?

Ну, как вы уже догадались, exec() делает свою магию в неблокирующий манере. Это хорошая штука, потому что таким образом мы можем выполнять очень дорогостоящие shell-операции (как, например, копирование больших файлов или что-то подобное), не заставляя наше приложение полностью останавливаться, пока блокирующая sleep-операция не выполнится.

Если хотите удостовериться, замените «ls -lah» на более дорогостоящую операцию «find /»).

Но мы не совсем довольны своей элегантной неблокирующей операцией, когда наш браузер не отображает её результат, не так ли?

Давайте тогда пофиксим это. Давайте попытаемся понять, почему текущая архитектура не работает.

Проблемой является то, что exec(), чтобы работать без блокирования, использует callback-функцию.

В нашем примере это анонимная функция, которая передаётся как второй параметр в функцию exec():

И здесь лежит корень нашей проблемы: наш собственный код исполняется синхронно, что означает, что сразу после вызова exec(), Node.js продолжит выполнять return content;. К этому моменту content ещё «empty», из-за того, что callback-функция, переданная в exec(), до сих пор не вызвана — потому что операция exec() асинхронная.

Теперь «ls -lah» — очень недорогая и быстрая операция (если только в директории не миллион файлов). Именно поэтому callback вызывается относительно оперативно — но это, всё же, происходит асинхронно.

Использование более дорогостоящих команд делает это более очевидным: «find /» занимает около 1 минуты на моей машине, но если я заменяю «ls -lah» на «find /» в обработчике запроса, то я всё ещё немедленно получаю HTTP-ответ, когда открываю URL /start. Ясно, что exec() делает что-то в фоновом режиме, пока Node.js продолжает исполнять приложение и мы можем предположить, что callback-функция, которую мы передали в exec(), будет вызвана только когда команда «find /» закончит выполняться.

Но как нам достичь нашей цели, то есть, показать пользователю список файлов в текущей директории?

Теперь, после изучения вопроса о том, как делать не надо, давайте обсудим, как заставить наши обработчики запроса реагировать на запросы браузера правильно.

Ответ обработчиков запроса с неблокирующими операциями.

Я употребил фразу «правильный способ». Опасная вещь. Довольно часто не существует единого «правильного способа».

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

Сейчас наше приложение способно транспортировать контент (который обработчики запроса хотели бы показать пользователю) от обработчиков запроса к HTTP-серверу, возвращая его через слои приложения (обработчик запроса -> роутер -> сервер).

Наш новый подход заключается в следующем: вместо доставки контента серверу мы будем сервер доставлять к контенту. Чтобы быть более точным, мы будем внедрять объект response (из серверной callback-функции onRequest()) через роутер в обработчики запроса. Обработчики смогут тогда использовать функции этого объекта для ответа на сами запросы.

Достаточно разъяснений. Вот — пошаговый рецепт изменения нашего приложения.

Начнём с нашего server.js:

Вместо ожидания возврата значения от функции route(), мы передаём наш объект response в качестве третьего параметра. Кроме того, мы удалили всякие вызовы методов response из обработчика onRequest(), потому что мы рассчитываем, что route позаботится об этом.

Далее идёт router.js:

Та же схема: вместо ожидания возврата значения от наших обработчиков события, мы передаём объект response.

Если обработчик запроса не может быть использован, мы заботимся об ответе с надлежащим заголовком «404» и телом ответа.

И последнее, но не менее важное, мы модифицируем requestHandlers.js:

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

Обработчик start будет отвечать изнутри анонимного обратного вызова exec(), а обработчик upload будет всё ещё выдавать «Hello Upload», но теперь посредством объекта response.

Если вы запустили наше приложение снова (node index.js), всё должно работать как и ожидалось.

Если хотите убедиться, что дорогостоящая операция в /start больше не будет блокировать запросы на /upload, модифицируйте ваш requestHandlers.js как показано далее:

Благодаря этому, HTTP-запросы к http://localhost:8888/start будут занимать не менее 10 секунд, но запросы к http://localhost:8888/upload будут получать ответ немедленно, даже если /start всё ещё занят вычислениями.

Сделаем что-нибудь полезное

До сих пор мы делали всё прекрасно и изысканно, но мы не создали ничего значимого для клиентов нашего супер-сайта.

Наш сервер, роутер и обработчики запроса находятся на своих местах, таким образом, теперь мы можем начать добавлять контент на наш сайт, который позволяет нашим пользователям выбирать файл, загружать его и просматривать загруженный файл в браузере. Для простоты будем полагать, что через наше приложение будут загружаться и показываться только файлы картинок.

OK, давайте шаг за шагом, но с разъяснением больших техник и принципов JavaScript, и в то же время, давайте немного ускоримся. Автору слишком нравится слушать самого себя.

Здесь «шаг за шагом» означает примерно 2 шага: сначала мы посмотрим как обрабатывать входящие POST-запросы (но не загрузку файла), и на втором шаге мы используем внешний модуль Node.js для обработки загрузки файла. Я выбирал этот подход по двум причинам.

Во-первых, обрабатывать базовые POST-запросы относительно просто в Node.js, но для обучения это — достаточно стоящее упражнение.
Во-вторых, обработка загрузки файла (к примеру, multipart POST-запросы) это не так просто в Node.js, поэтому выходит за рамки этого учебника, но пример использования для этого внешнего модуля имеет смысл включить в учебник для начинающих.

Обработка POST-запросов

Давайте сделаем попроще: предоставим текcтовое поле, которое может быть заполнено пользователем и отправлено на сервер в POST-запросе. После получения и обработки этого запроса мы отобразим содержимое текстового поля.

HTML-код для формы текстового поля должен формировать наш обработчик запроса /start, так давайте сразу же добавим его в файл requestHandlers.js:

Если теперь этот код не выиграет Webby Awards, то я не знаю, какой сможет. Вы должны увидеть эту очень простую форму, когда запросите http://localhost:8888/start в вашем браузере. Если это не так — возможно, вы не перезагрузили приложение.

Я уже слышу вас: помещать содержимое представления прямо в обработчик запроса некрасиво. Тем не менее, я решил не включать этот дополнительный уровень абстракции (то есть, разделение представления и логики) в наш учебник, потому что, я думаю, что это не научит нас чему-нибудь стоящему в контексте JavaScript или Node.js.

Давайте лучше использовать появившееся окно для более интересных проблем, то есть, обработки POST-запроса в нашем обработчике запроса /upload при отправке этой формы пользователем.

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

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

Чтобы сделать весь процесс неблокирующим, Node.js обслуживает POST-данные небольшими порциями, а callback-функции вызываются при определённых событиях. Эти события — data (когда приходит новая порция POST-данных) и end (когда все части данных были получены).

Надо сообщить Node.js, какие функции вызывать, когда эти события произойдут. Это делается путём добавления слушателей (listeners) в объект request, который передаётся в нашу callback-функцию onRequest, когда HTTP-запрос получен.

В основном, это выглядит так:

Возникает вопрос, где реализовать эту логику. В настоящее время мы можем получить доступ к объекту request только в нашем сервере — мы не передаём его в роутер и в обработчики запроса, как делаем это с объектом response.

На мой взгляд, это работа HTTP-сервера — предоставлять приложению все данные из запросов. Поэтому я предлагаю обрабатывать POST-данные прямо в сервере и передавать конечные данные в роутер и обработчики запроса, которые сами решат, что с ними делать.

Таким образом, идея — в том, чтобы поместить обратные вызовы событий data и end в сервер, собирать все куски POST-данных в data и вызывать роутер при получении события end, пока идёт передача собранных порций данных в роутер, который в свою очередь передаёт их в обработчики запроса.

Начинаем с server.js:

Здесь, в основном, мы сделали три вещи: во-первых, определили, что ожидаем полученные данные в кодировке UTF-8, затем добавили слушатель для события «data», который шаг за шагом заполняет нашу новую переменную postData всякий раз, когда прибывает новая порция POST-данных, и далее — переходим к вызову нашего роутера в обратном вызове события end, чтобы убедиться, что вызов происходит, когда все POST-данные собраны. Мы также передаём POST-данные в роутере, потому что они нам понадобятся в обработчиках запроса.

Добавление логирования в консоли для каждой порции полученных данных — возможно, плохая идея для конечного кода (мегабайты POST-данных, помните?), но это имеет смысл, чтобы посмотреть, что происходит.

Я предлагаю немного поиграться с этим. Поместите в текстовое поле сначала немного текста, а потом больше, и вы увидите, что для больших текстов обратный вызов data действительно вызывается несколько раз.

Давайте добавим ещё больше крутизны в наше приложение. На странице /upload мы будем показывать принятый контент. Чтобы сделать это возможным, нам необходимо передавать postData в обработчики запроса. В router.js:

И в requestHandlers.js мы включаем эти данные в нашем ответе обработчика запроса upload:

Вот и всё, теперь мы можем получить POST-данные и использовать их в наших обработчиках запроса.

И последнее по этой теме: то, что мы передаём в роутер и обработчики запроса, является полным телом нашего POST-запроса. Мы, вероятно, захотим использовать индивидуальные поля, составляющие POST-данные, в нашем случае значение поля text.

Мы уже читали про модуль querystring, который поможет нам с этим:

Это всё, что можно сказать про обработку POST-данных в рамках учебника для начинающих.

Обработка загрузки файлов

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

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

Внешний модуль, который мы собираемся использовать, node-formidable от Felix Geisendörfer. Этот модуль поможет нам абстрагироваться от мерзких деталей парсинга входящих файловых данных. В конце концов, обработка входящих файлов это не что иное, как «просто» обработка POST-данных, но, в действительности, дьявол кроется в деталях, поэтому в нашем случае имеет смысл использовать готовое решение.

Чтобы использовать код Феликса, соответствующий модуль Node.js должен быть инсталлирован. На борту Node.js есть собственный менеджер пакетов, называемый NPM. Он позволяет нам инсталировать внешние модули Node.js в очень удобной форме. С учетом установленного Node.js, всё сводится к

в нашей командной строке. Если вы в конце увидели следующее:

. это значит — всё хорошо.

Модуль formidable теперь доступен в нашем коде — всё, что нужно, это просто запросить его как один из тех модулей, которые мы использовали ранее:

По сути, formidable делает форму, отправленную через HTTP POST, доступной для парсинга в Node.js. Всё, что нам надо — это создать новый экземпляр объекта IncomingForm, который является абстракцией отправленной формы и может быть использован для парсинга объекта request нашего HTTP-сервера, для полей и файлов, отправленных через эту форму.

Пример кода со страницы проекта node-formidable показывает, как разные части сочетаются друг с другом:

Если вы поместите этот код в файл и исполните его посредством node, вы сможете отправлять простые формы, включая загрузку фото, и увидите, как организован объект files, который передавался в callback, определенном в вызове form.parse.

Чтобы выполнить последний пункт нашей задачи, мы должны включить логику парсинга форм модуля formidable в структуру нашего кода, плюс ко всему, надо разобраться, как отдавать контент загруженного файла (который сохранен в директории /tmp) браузеру.

Давайте сначала решим последнюю задачу: если имеется файл картинки на вашем локальном диске, что сделать, чтобы передать его браузеру?

Мы, очевидно, собираемся считать содержимое этого файла в наш Node.js-сервер, и неудивительно, что для этого имеется соответствующий модуль под названием fs.

Давайте добавим ещё один обработчик запроса для URL /show, который будет «захардкоженно» показывать содержимое файла /tmp/test.png. Конечно же, имеет смысл в первую очередь поместить реальную png-картинку в этот каталог.

Мы собираемся изменить requestHandlers.js, как показано далее:

Также, надо преобразовать новый обработчик запроса в URL вида /show в файле index.js:

Перезапускаем сервер, открываем http://localhost:8888/show в браузере и видим картинку /tmp/test.png.

Хорошо. Всё, что нам надо теперь — это:

  • добавить поле для загрузки файлов в форму, находящуюся по адресу /start,
  • интегрировать node-formidable в обработчик запроса upload, чтобы сохранять загруженные файлы в /tmp/test.png,
  • внедрить загруженную картинку в HTML, отдаваемый по URL /upload.

Первый шаг — простой. Нам надо добавить тип кодировки multipart/form-data в нашу HTML-форму, удалить текстовое поле, добавить поле загрузки файла и поменять текст кнопки отправки формы на «Upload file». Давайте просто сделаем это в файле requestHandlers.js:

Замечательно. Следующий шаг — немного более сложный, конечно. Первая проблема следующая: мы хотим обрабатывать загрузку файлов в нашем обработчике запроса upload, и тут надо будет передать объект request при вызове form.parse модуля node-formidable.

Но всё, что у нас есть — это объект response и массив postData. Грустно. Похоже, что придётся передавать каждый раз объект request из сервера в роутер и обработчик запроса. Может быть, имеется более элегантное решение, но этот способ может делать работу уже сейчас.

Мастер Йода рекомендует:  LocalStorage на пальцах

Давайте полностью удалим всё, что касается postData в нашем сервере и обработчиках запроса — он нам не нужен для обработки загрузки файла и, мало того, — даже создает проблему: мы уже «поглотили» события data объекта request в сервере, а следовательно, form.parse, которому так же надо поглащать эти события, не сможет получить больше данных (потому что Node.js не буферизирует данные).

Начнём с server.js — удалим обработку postData и строку с request.setEncoding (node-formidable сам всё сделает) и передадим request в роутер:

Следующий — router.js — мы больше не передаём postData, а вместо этого передаём request:

Теперь объект request может быть использован в функции обработчика запроса upload. node-formidable будет заниматься сохранением загруженного файла в локальный файл /tmp, но, конечно, мы сами должны сделать, чтобы этот файл переименовывался в /tmp/test.png. Да, мы придерживаемся действительно простых вещей и принимаем, что могут загружаться только PNG-картинки.

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

Давайте добавим в requestHandlers.js код управления загрузкой файла и переименованием:

Вот и всё. Перезапускаем сервер, и последний пункт нашей задачи реализован. Выбираем локальную PNG-картинку с диска, загружаем на сервер и видим её на нашей веб-страничке.

Выводы и перспективы

Поздравляю, наша миссия выполнена! Мы написали простое, уже полностью готовое web-приложение на Node.js. Мы поговорили о server-side JavaScript, функциональном программировании, блокирующих и неблокирующих операциях, callback-ах, событиях, обычаях, внутренних и внешних модулях и о многом другом.


Конечно, имеется много вещей, которые мы не обсудили: как общаться с базой данных, как писать unit-тесты, как создавать внешние модули, с возможностью инсталяции через NPM или даже что-нибудь простое, например, как обрабатывать GET-запросы.

Но это судьба каждого учебника, предназначенного для начинающих — нельзя расказать о всех аспектах во всех деталях.

Web разработка на node.js и express

###Изучаем node.js на практике

Приветствую, перед вами небольшой учебник по практической разработке на node.js, с использованием фреймворка express. Я с большим энтузиазмом отношусь к node и сопутствующим технологиям. Node.js в первую очередь привлекает свежестью в подходах к разработке, смелостью и драйвом.

О том, что такое node.js вы можете прочитать на http://nodejs.org/, если коротко — то это серверная платформа, для выполнения javascript. Так же мы будем использовать express, web-фреймворк построеный на концепции middleware (о том, что это такое, поговорим поподробнее чуть позже)

В процессе изучения мы познакомимся с различными аспектами web-разработки, такими как использование системы контроля версий, автоматическое тестирование и так далее. В результате по ходу изучения мы разработаем вполне рабочее web-приложение (простенький аналог твиттера)

Хочется отметить, что очень большое влияние на меня оказал railstutorial, это лучшее пособие по web-разработке, которое я встречал, и мне очень хотелось бы создать нечто подобное для node.js.

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

Так как я в основном использую в работе linux, а если точнее — Ubuntu 12.04, основная часть инструкций по установке тех или иных инструментов будет ориентирована на ползователей линукс, но я буду стараться по возможности давать ссылки на инструкции и для других ОС.

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

Так что, первое что мы сделаем — это.

Пользователи apt-based дистрибутивов могут выполнить в терминале:

Остальные отправляются читать инструкции по адресу http://git-scm.com/book/ch1-4.html

Теперь пришло время поставить последнюю стабильню версию node.js и npm (установщик пакетов для node).

Инструкции по установке разных ОС можно найти здесь

Для установки на ubuntu выполняем:

Если есть желание — можно запустить консоль node и поиграться с интерпретатором javascript.

Тут каждый волен выбирать по своему вкусу, лично меня вполне устраивает gedit с установленным набором плагинов gmate. Вполне подходят Netbeans или Webstorm.

Теперь пришло время познакомиться с фреймворком express. Фреймворк очень простой, и вполне приемлемо документированный.

Устанавливаем express глобально:

Создаем директорию для наших учебных проектов:

Создаем проект и устанавливаем зависимости:

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

Теперь приложение можно запустить:

И увидеть результат работы http://localhost:3000/

Теперь, когда у нас уже есть рабочее приложение, более подробно коснемся работы с сисемой контроля версий. Для того чтобы лучше познакомиться с работой git, стоит почитать книжку Pro Git, но можно и обойтись инструкциями в данном учебнике.

Для более комфортной работы с git стоит сначала указать свои личные данные:

И настроить алиасы для наиболее часто используемых комманд:

Git настроен и можно размещать наше приложение в репозитории, инициализируем новый репозиторий:

Добавляем директорию с зависимостями приложения в gitignore:

Помещаем все файлы в индекс и создаем первый коммит:

После размещения кода проекта в репозитории пришло время выложить проект на GitHub. GitHub — это социальная сеть и хостинг для проектов. Огромное число opensource проектов хостится на гитхабе, так что если вы там еще не зарегистрированы — самое время сделать это.

Перед тем как работать с GitHub нужно будет создать RSA ключи для доступа по ssh. Процедура описана тут. Для пользователей linux привожу инструкцию по созданию ключей если их у вас еще нет.

Отвечаем на вопросы генератора, после чего копируем содержимое файла

После этого нужно пройти по ссылке Account Settings, зайти в раздел SSH Keys и нажать кнопку Add SSH Key и вставить ключ из буфера обмена в поле Key. Затем сохранить.

Проверить что ключ работает можно так:

Возможно вы увидете предупреждение:

Нужно просто ответить ‘yes’ и тогда, если ключ успешно добавился, вы увидите ответ сервера:

Когда ключи настроены создаем новый репозиторий с названием first-app и дефолтными настройками, после чего выкладываем код на гитхаб:

Теперь наступает самый волнующий этап, мы будем разворачивать приложение на хостинге. Для этого воспользуемся услугами облачной системы деплоя Heroku. Если вам интересно как работает хостинг Heroku, советую поизучать их раздел How it Works

Для начала нам надо зарегистрироваться и установить необходимый инструментарий.

Пользователи ubuntu выполняют:

Когда установка завершится, нужно будет залогиниться из коммандной строки:

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

В файле package.json нашего проекта, нужно указать версии ноды и npm, package.json должен выглядеть так:

Теперь в корне проекта создаем файл Procfile:

Проверяем что все запускается с помощью менеджера процессов:

Приложение должно быть доступно на http://localhost:5000/

Добавляем файлы в репозиторий:

Создаем приложение на heroku:

и любуемся задеплоеным приложением.

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

Перед тем как приступать собственно к разработке приложения, полезно поговорить о том, что из себя представляет типичная архитектура web-приложения на наиболее высоком уровне абстракции. Самым популярным архитектурным паттерном на сегодняшний день является model-view-controller (MVC), общий смысл паттерна заключается в том, чтобы разделить бизнес логику приложения (её привязывают к моделям) и представление — view. Кроме того, модели реализуют интерфейс к базе данных. Контроллер играет роль посредника между моделью и представлением. В случае web-приложения — это выглядит так: браузер пользователя отправляет запрос на сервер, контроллер обрабатывает запрос, получает необходимые данные из модели и отправляет их во view. View получает данные из контроллера и превращает их в красивую HTML страничку, которую контроллер в итоге отправит пользователю.

Пришло время приступить к разработке нашего демонстрационного приложения. В первой главе мы уже развернули тестовое приложение, но воспользовались при этом генератором express и не написали ни строчки кода. Теперь мы будем писать наше приложение сами и начнем с «Hello, World».

Что такое npm? Все просто, это node package manager (хотя авторы это оспаривают). В общих чертах пакет npm — это директория содержащая программу и файл package.json, описывающий эту программу, в том числе в этом файле можно указать от каких других пакетов зависит наша программа, почитайте описание package.json. Для того чтобы воспользоваться всеми прелестями, которые нам может предоставить npm, мы создадим в корневой директории нашего проекта файлик:

Теперь можно выполнить

В результате npm создаст директорию node_modules в которую поместит все модули от которых зависит наш проект.

Основной файл назовем server.js:

Сразу определимся с терминологией и разберем этот код. Нашим приложением будет объект app , вызов функции app.get монтирует экшн (action), роль которого в данном случае выполняет анонимная функция, к пути (route) ‘/’. Фактически это означает, что каждый раз при получении http запроса GET /, приложение выполнит указанный экшн. Переменная port в этом примере инициализируется переменной окружения PORT при её наличии, а если такой переменной нет, то принимает значение 3000. app.listen запускает http-сервер на указанном порте и начинает слушать входящие запросы.

Для того, чтобы полюбоваться результатом нашего труда, есть два способа:

Второй способ доступен потому что мы добавили соответствующую строчку в файл конфигурации package.json в разделе «scripts».

Теперь по адресу http://localhost:3000/ можно получить строчку ‘Hello, World!’.

Настало время залить что-нибудь в GitHub. Создаем новый репозиторий на GitHub с названием node-demo-app и выполняем в директории проекта следующий набор комманд, сперва создадим файл README.md (правило хорошего тона)

Создадим файл .gitignore для того чтобы не коммитить лишние файлы в git, а именно директорию node_modules:

Возможно кто-то читал статью Mikeal Rogers и хотел бы возразить против добавления node_modules в .gitignore. Для тех кому лень читать, в проектах на node.js рекомендуется такой подход:

  • Для проектов которые мы разворачиваем, таких как веб-приложения, node_modules помещаются в репозиторий.
  • Для библиотек и другого повторно используемого кода node_modules не добавляются в репозиторий.
  • Для развертывания на production npm не используется.

Но! Мы в качестве хостинга используем Heroku и способ деплоя не выбираем, а там node.js проекты деплоятся с помощью npm, так что не будем замусоривать репозиторий.

Создаем репозиторий, коммитимся и заливаем все на GitHub:

Express пока не диктует строгой структуры для файлов приложения, так что мы придумаем свою. Предлагаю такой вариант:

Никто не заставляет придерживаться именно такой схемы расположения файлов, но мне она кажется удобной, так что просто запомним эту картинку и по мере продвижения по туториалу будем создавать необходимые файлы и директории.

О том что такое TDD и зачем нужно писать тесты вы наверняка уже слышали, а если нет, то можете прочитать об этом здесь. В этом учебнике для тестирования приложения мы воспользуемся подходом, который называется BDD (behavior-driven development). В тестах мы будем описывать предполагаемое поведение приложения. Сами тесты разделим на две категории: integration тесты — они будут имитировать поведение пользователя и тестировать систему целиком, и unit тесты — для тестирования отдельных модулей приложения.

В качестве фреймворков для написания тестов мы будем использовать библиотеки mocha (читается как мокка, кофе-мокка :)), should.js, и supertest. Mocha служит для организации описаний тест-кейсов, should.js предоставляет синтаксис для осуществления различных проверок, а supertest — это надстройка над простеньким http-клиентом, которая позволяет проверять результаты http-запросов. Для подключения библиотек сделаем необходимые изменения в package.json

Зависимости мы разместили в разделе «devDependencies», так как нет никакой необходимости тащить эти библиотеки на продакшн сервер. Для установки библиотек выполняем

Для того что бы понять как это работает, попробуем создать свой первый тест и прогнать его через наш фреймворк

В test.js положим такой тест

Вполне естественно, что такой тест пройдет, так что заменим его на что-то неработающее

и видим, что тесты не прошли, придется чинить код, добавляем объявление переменной

и видим что код рабочий.

Основной принцип TDD состоит в том, чтобы написать тесты до того как написан код, таким образом мы можем убедиться в том, что тесты действительно что-то тестируют, а не просто запускают код на выполнение и делают проверки в стиле true.should.be.true. То есть процесс разработки выглядит следующим образом:

  1. Пишем тест
  2. Выполняем тест и убеждаемся в том что он падает
  3. Пишем код
  4. Выполняем тест и убеждаемся в том что он проходит, если нет, возвращаемся в п.3

И так много раз.

Чтобы упростить запуск тестов добавим таск прогоняющий тесты в Makefile

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

Теперь test-suite можно запускать коммандой:

Попробуем потестировать http запросы. Для того чтобы сделать тестирование более удобным проведем небольшой рефакторинг кода и вынесем приложение express из файла server.js в отдельный модуль app/main.js, а также создадим файл app.js который будет этот модуль экспортировать. Сейчас это может выглядеть нецелесообразным, но такой способ организации кода нам пригодится, когда мы будем проверять покрытие кода тестами.

server.js заменяем на

Для того чтобы понять как работают модули node.js, а также что означают require и module.exports читаем документацию

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

В этом тесте мы проверяем, что сервер отвечает нам строчкой «Hello, Express!». Так как вместо этого сервер отвечает «Hello, World!», тест упадет. Важный момент, на который нужно обратить внимание, запросы к http серверу происходят асинхронно, по-этому нам нужно будет назначить callback на завешение теста. Mocha предоставляет такую возможность с помощью функции done, которую можно опционально передать в функцию с тест-кейсом. Чтобы тест прошел, нужно заменить строчку «Hello, World!» на «Hello, Express!» в файле app/main.js и выполнить make test .

В принципе, этот параграф можно пропустить, так как на процесс написания тестового приложения он никак не влияет, но отчет о покрытии кода тестами будет приятным дополнением к нашему test-suite.

Чтобы выяснить насколько полно наш код покрыт тестами, потребуется еще один инструмент, он называется jscoverage. Его придется скомпилировать. Так что если у вас еще не установлен компилятор, стоит его поставить:

После чего устанавливаем jscoverage:

Вернемся в директорию проекта:

Нам потребуется внести некоторые изменения в Makefile и app.js чтобы иметь возможность генерировать отчеты о покрытии.

Мы добавили таск test-cov в Makefile так что теперь для генерации отчета coverage.js достаточно будет запустить make test-cov . Изменения в app.js связаны с тем, что для генерации отчета используется инструментированная копия приложения, которую генерирует jscoverage. То есть мы проверяем переменную окружения APP_COV и если она установлена загружаем приложение из директории /app-cov, а если нет, то берем обычную версию из /app.

Должен появиться файл coverage.html, который можно открыть в браузере.

Осталось добавить в .gitignore app-cov и coverage.html:

С тестами мы разобрались, так что удаляем тестовый тест

Конечно статические страницы можно сделать по настоящему статическими, то есть разместить файл к примеру index.html со следующим содержанием:

в директории public, и научить приложение отдавать его как статику. Делается это с помощью добавления строчки app.use(express.static(__dirname + ‘/public’)) в app.js

Все файлы в директории /public после этого будут отдаваться как статика http://localhost:3000/index.html. Но нам это не очень интересно, так что стираем ненужный index.html

Раз уж мы решили придерживаться TDD, то первым делом напишем тест для еще не созданного контроллера pages

Тут мы описали такие сценарии:

  • GET ‘/’ должен редиректить на ‘/home’
  • GET ‘/home’ должен быть успешным
  • GET ‘/home’ должен в теле ответа содержать строку «Home page»

Убеждаемся в том что они все падают.

Наша цель в том, чтобы тесты прошли. Создаем контроллер для раздачи статичных страничек:

В этом контроллере создадим экшн, который будет отдавать нам домашнюю страничку приложения

Теперь подключим контроллер страниц, экшн примонтируем к пути ‘/home’, а для пути ‘/’ настроим редирект на ‘/home’ в app.js

Запускаем тесты, если мы все сделали правильно, они должны пройти.

При попытке зайти на http://localhost:3000/ нас теперь перекинет на страничку home. С контроллером разобрались, теперь возьмемся за вьюхи.

Express в качестве движка для шаблонизации позволяет подключать разные библиотеки, такие как ..placeholder.. Мы воспользуемся ejs т.к. как ее синтаксис приближен к html и возможно привычен большинству. Для этого в package.json добавим зависимость «ejs»: «0.8.3»

EJS нужно подключить к приложению в app.js

Шаблоны мы будем хранить в директории ‘/views’ с поддиректорией для каждого контроллера и начнем с шаблона для страницы home

В этом файле можно разместить шаблон для странички и использовать переменные, которые туда передаст контроллер, например

В данном случае используются переменные title и message . И поменяем экшн home в контроллере pages

Наша «статическая» страница стала уже слегка «динамической». Любуемся результатом по адресу http://localhost:3000/home.

В принципе в этот момент было бы неплохо закомититься, предварительно прогнав тесты и убедившись, что наши улучшения ничего не поломали. Вообще это нужно принять за правило, перед коммитом всегда прогоняем test-suite.

Предлагаю в качестве упражнения самостоятельно сделать страничку about, добавив необходимый экшн в контроллер pages и создав шаблон для неё. Не забываем примонтировать путь ‘/about’ в app.js. Ну а начать нужно с тестов!

Если у вас получилось создать страницу «/about» то теперь у вас две страницы, если не получилось, можете выкачать готовый вариант из гитхаба

Как вы могли заметить, в наших вьюшках дублируется код и хотелось бы устранить этот недочет. Для этого создадим layout с базовым каркасом страницы. К сожалению ejs пока что не поддерживает layout-ы, но существует библиотека ejs-locals, которая добавляет этот функционал в шаблонизатор. Подключаем её в проект.

Добавляем в приложение app.js:

Этот файл будет общим каркасом для страниц, а конкретная вьюха будет рендериться на месте тега .

Теперь можно убрать лишний код из шаблонов home.ejs и about.ejs. Сейчас они идентичны и мы могли бы воспользоваться одним шаблоном для обоих экшнов, но как правило разные страницы имеют разный код так что представим себе, что он различается.

home.ejs и about.ejs:

Внешне ничего не должно поменяться, чтобы убедиться в этом запустим tet-suite, а потом закоммитимся

Осталось навести красоту, в этом нам поможет фреймворк для прототипирования под названием Twitter Bootstrap, его нужно скачать и положить в /public

Теперь воспользуемся шаблоном Bootstrap starter template и сделаем layout на его основе:

Чтобы добавить в шаблон переменную route , которую мы используем для подсветки ссылки на текущую страницу, добавим немножко кода в app.js.

Выполняем стандартную процедуру:

Любуемся получившейся красотой на http://localhost:3000/.

Мы уже разворачивали приложение в первой главе, так что просто повторим процесс. Добавляем версии node.js и npm в package.json:

Отправляем приложение на heroku:

Suspendisse hendrerit quam mollis magna pharetra ac convallis justo laoreet. Morbi sit amet malesuada arcu. Sed adipiscing tempus rutrum. Aenean lacinia metus et augue aliquam pulvinar. Praesent nulla ante, ullamcorper vitae varius quis, ullamcorper sit amet risus. Nulla facilisi. Ut risus arcu, convallis a ornare eu, tempor sed elit. Mauris auctor, tellus cursus congue convallis, lorem neque hendrerit turpis, at viverra erat ipsum ut nunc. Fusce non lectus massa, vitae imperdiet lorem. Curabitur dapibus ullamcorper est, ut vestibulum diam sollicitudin sit amet.

Введение в JavaScript

Этот пост посвящён главному языку будущего — JavaScript. Благодаря своей гибкости используется в браузере, на серверах, в мобильных приложениях, на десктопе и практически во всех видах программирования. Удобный синтаксис позволяет легко писать на нём, а высокая производительность делает его отличным выбором для решения любых задач — от небольших магазинов до огромных highload проектов. JavaScript по праву является самым популярным в мире языком. На каждом сайте есть браузерный JavaScript, а JavaScript на сервере используется такими крупными корпорациями, как Amazon, Yahoo, HP, NASA, Walmart и многие другие.

Часто задаваемые вопросы

В: Что это за язык такой?

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

В: Какие возможные направления для разработки существуют?

О: Практически все! Можно писать Front-end, Back-end, GameDev, 2D/3D графику, разрабатывать мобильные и десктопные приложения. Список инструментов для различных целей

В: Можно выучить только один фреймворк/библиотеку и всё писать на нём?

О: Не стоит начинать учить отдельный фреймворк или библиотеку, пока отсутствуют базовые знания самого языка. Во-первых, из-за отсутствия знаний самого языка возникнет масса проблем с пониманием принципа работы фреймворка/библиотеки, во-вторых, этим можно сильно испортить себе восприятие языка и после этого будет гораздо сложнее изучать чистый JS и другие фреймворки.

В: Существуют ли стайл-гайды для JavaScript?

В: Какие новые возможности добавил ES6?

О: Вот здесь можно почитать на русском

В: Я хочу писать на ES6, но многие браузеры не поддерживают новые возможности. И вообще, надоел геморрой с браузерным зоопарком. Неужели нет способа обойти это?

О: Конечно есть! Чтобы код одинаково хорошо работал во всех браузерах и все возможности ES6 и будущих стандартов нормально работали необходимо собрать код с помощью сборщика. Сборщик компилирует весь код в один файл и делает его полностью кроссбраузерным. Наиболее удобен в использовании Webpack, хотя существуют и аналоги. Потребуется некоторое время на изучение, но результат себя окупит. Сборщики нужны только во Front-end, Node.js и так поддерживает все новые возможности.

В: Зачем нужны CoffeeScript и TypeScript?

О: Это особые варанты JS для любителей других языков. CoffeeScript подходит для любителей Ruby и Python, TypeScript — для сторонников строготипизированных языков вроде C# или Java. Если ты новичок в программировании, то учи оригинал, а диалекты попробуешь, когда уже будет опыт.

В: Зачем нужны таск-раннеры, такие как Gulp или Grunt?

О: Они позволяют одной консольной командой запустить выполнение заранее прописанного процесса, который может содержать множество команд и который неудобно каждый раз выполнять вручную. Пример — компиляция JS с помощью Webpack, сборка LESS стилей в CSS и многое другое. Ещё раз — таск-раннер не замена сборщику, Gulp — не конкурент Webpack, они выполняют совершенно разные задачи и зачастую используются вместе.

В: Можно ли писать фронт на других языках?

О: Да, существуют компиляторы различных языков в JS, такие как ScalaJS, PyJS и другие. Но стоит помнить, что у них есть масса недостатков и использовать их стоит только если на чистом JS (также CS и TS) не получается писать совершенно. Они предназначены прежде всего для тяжёлых приложений вроде браузерных 3D игр в классических Front-end целях не очень удобны.

В: Я слышал про какой то WebAssembly, который заменит JS. Это правда? Что это такое?

О: Нет, неправда. WebAssembly (WASM) практически не имеет отношения к классическому Front-end. Это особая технология, позволяющая выполнять в браузере бинарный код, компилируемый из различных языков. Он предназаначен для выполнения в браузере тяжёлых приложений вроде трёхмерных онлайн-игр и никак не связан с привычными задачами JS. Более того, учитывая развитую инфраструктуру JS, множество фреймворков и библиотек на все случаи жизни, большое количество профессиональных разработчиков, огромное количество легаси-кода, выполнение WASM иных задач, не связанных с различными высокопроизводительными трёхмерными приложениям, видится невозможным. Кроме того, WASM не затрагивает серверную и мобильно-десктопную часть JavaScript, которые уже успели стать довольно популярными.

В: С чего начать изучение?

Материалы для изучения

Книги про JavaScript

Марейн Хавербек — «Выразительный JavaScript» — Вводная книга по JavaScript и программирование в целом.

Дэвид Фленеган — «JavaScript: Подробное руководство«

Дуглас Крокфорд «JavaScript: сильные стороны«

Стефанов С. — «JavaScript. Шаблоны«

Джон Резиг — «Секреты JavaScript ниндзя«

Николас Закас — «JavaScript. Оптимизация производительности«

Джон Резиг, Расс Фергюсон — «JavaScript для профессионалов«

Dr. Axel Rauschmayer — «Speaking JavaScript: An In-Depth Guide for Programmers«

Discover Meteor — Книга по Meteor.js — одному из самых лёгких и функциональных фреймворков.

М. Кантелон , М. Хартер — «Node.js в действии«

Кирилл Сухов — «Node.js. Путеводитель по технологии«

Дэвид Хэррон — «Node.js. Разработка серверных веб-приложений»

Тодд Мотто — «Учебник AngularJS«

Max P — «Курс по React.js для начинающих«

Эдди Османи — «Разработка Backbone.js приложений«

Эрл Каслдайн, Крэйг Шарки — «Изучаем JQuery«

Адам Фримен — «jQuery для профессионалов«

И не забываем читать официальную документацию для каждого фреймворка.

learn.javascript.ru — Самый главный русскоязычный сайт по JavaScript. Других таких подробных уроков не найти. Начинать строго с него.

node-center.ru — Второй по важности сайт. Ориентирован на Node.js, но мелькает материал и по Front-end. Сборник всей нужной информации, перевод официальной документации, список книг и ссылок.

jstherightway.org — Огромный англоязычный гайд. Есть книги, статьи, список фреймворков и многое другое. По сути, этот текст — краткий аналог этого гайда.

nodeguide.ru — Большое количество переведённых статей по Node.js

Блоги и новостные ленты

weblog.bocoup.com — Bocoup Weblog

perfectionkills.com — Perfection Kills

reddit.com/r/javascript — subreddit на reddit.com

toddmotto.com — Todd Motto, Lead front-end @appsbroker . Developer Expert @google .

Изучая только теорию язык усваивается плохо. Наиболее важна практика, которую можно получить на онлайн-курсах.

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

Уже не такой сильный, но все еще интересный проект, также обязателен для улучшения навыка.

Дает хорошее представление о замыканиях.

Прошёл курсы, прочитал книги и думаешь, что знаешь JS? Теперь изучи тонкости и особенности языка. Сделать это можно здесь — https://shamansir.github.io/JavaScript-Garden/

Список инструментов для различных целей

Frontender Magazine

Сейчас нет недостатка в обучающих материалах по Node.js, но большинство из них охватывают либо какие-то конкретные варианты использования, либо темы, применимые уже тогда, когда у вас есть работающий Node.js То тут, то там я вижу комментарии вроде «я скачал Node.js, что теперь?». Статья ответит на этот вопрос и объяснит, как начать с самого начала.

Что есть Node.js?

Много путаницы у новичков в Node.js возникает из-за непонимания того, что же на самом деле это такое. И описание на nodejs.org не слишком помогает разобраться.

Важно понять, что Node — это не веб-сервер. Сам по себе он ничего не делает. Это не Apache. Там нет конфиг-файла, в котором указывается путь до HTML-файлов. Если вам нужен HTTP-сервер, вам нужно написать HTTP-сервер (с помощью встроенных библиотек). Node.js — это просто ещё один способ выполнять код на вашем компьютере. Это просто среда для выполнения JavaScript.

Установка Node

Установить Node.js очень просто. Если вы используете Windows или Mac, установочные файлы доступны на странице загрузки.

Я установил Node, что теперь?


Сразу после установки вам становится доступна новая команда node . Её можно использовать двумя разными способами. Первый способ — без аргументов. Откроется интерактивная оболочка (REPL: read-eval-print-loop), где вы можете выполнять обычный JavaScript-код.

В примере выше я написал console.log(‘Hello World’) в оболочке и нажал Enter. Node.js выполнит этот код, и мы увидим сообщение. undefined после него выводится потому, что оболочка отображает возвращаемое значение каждой команды, а console.log ничего не возвращает.

Кроме того, мы можем передать Node файл с JavaScript для выполнения. Именно так вы и будете практически всегда делать.

Теперь запустим его в терминале:

В этом примере я переместил console.log в файл, который затем передал команде node в качестве аргумента. Node затем запускает JavaScript из этого файла и выводит Hello World .

Делаем что-нибудь полезное — работа с файлами

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

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

Сперва нам нужно считать содержимое файла.

Работать с файлами в Node.js очень просто благодаря встроенному модулю файловой системы fs . Этот модуль содержит функцию readFile, принимающую в качестве аргументов путь до файла и коллбэк. Коллбэк вызовется, когда завершится чтение файла. Данные из файла поступают в виде объекта типа Buffer, по сути представляющего собой массив байтов. Мы можем перевести его в строку с помощью функции toString().

Мастер Йода рекомендует:  8 крутых Youtube-каналов, которые помогут изучить Java

Теперь давайте займёмся обработкой логов. Это вполне себе обычный код JavaScript, поэтому я не буду вдаваться в детали.

Теперь, когда вы передадите этот файл node в качестве аргумента, он выведет результат и завершит работу.

Я часто использую Node.js для таких задач. Это простая и мощная альтернатива bash-скриптам.

Асинхронные коллбэки

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

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

Делаем что-нибудь полезное — HTTP-сервер

Как я уже говорил ранее, Node.js не делает ничего «из коробки». Один из встроенных модулей позволяет без особых усилий создать простой HTTP-сервер, указанный в примере на сайте Node.js.

Когда я говорю, «простой», это значит «простой». Это не навороченный HTTP-сервер. Он не работает с HTML или изображениями. Фактически, что бы вы ни запросили, он вернёт Hello World . Тем не менее, можете запустить его, зайти на http://localhost:8080 в браузере и увидеть этот текст.

Возможно, вы заметите небольшую разницу: ваше приложение не завершает работу. Так происходит потому, что вы создали сервер, и теперь он будет продолжать работать и отвечать на запросы до тех пор, пока вы не убьёте node сами.

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

Делаем что-нибудь полезное — Express

Express — это фреймворк, делающий создание большинства сайтов очень простым. Первое, что вам нужно будет сделать — установить его. Вместе с командой node у вас появилась команда npm . Этот инструмент даёт вам доступ к колоссальному количеству модулей, созданных сообществом, и Express как раз один из них.

Установленный модуль расположится в папке node_modules внутри каталога с вашим приложением. Оттуда вы сможете подключать его так же, как любой встроенный модуль. Давайте создадим с помощью Express простой сервер, отдающий статику.

Теперь у вас есть довольно мощный сервер для статического контента. Всё, что вы сложите в папку /public , может быть запрошено из браузера и будет отображено. HTML, изображения, почти всё, что душе угодно. Например, если вы положите изображение с именем my_image.png в эту папку, его можно будет запросить по адресу http://localhost:8080/my_image.png . Разумеется, у Express намного больше возможностей, но их вы можете открыть для себя, продолжив изучение самостоятельно.

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

В предыдущем примере мы установили Express вручную. Если у вашего проекта много зависимостей, то устанавливать их таким образом не очень удобно, поэтому npm использует файлы package.json .

Файл package.json содержит общие сведения о вашем приложении. Он может содержать множество настроек, но выше указан необходимый минимум. Секция dependencies описывает имя и версию модулей, которые вы хотите установить. В данном случае подойдёт любая версия Express 3.3. Вы можете перечислить в этой секции столько зависимостей, сколько захотите.

Теперь вместо установки зависимостей по одной мы можем установить все сразу командой:

При запуске этой команды npm будет искать package.json в текущей директории, и если найдёт, то установит каждую указанную в нём зависимость.

Организация кода

Итак, до этого момента мы работали только с одним файлом, что не очень хорошо с точки зрения поддержки кода. В большинстве приложений вы будете распределять код между несколькими файлами. На данный момент какого-либо стандарта или рекомендуемой структуры файлов не существует. Это не Rails. Здесь нет концепта «представления идут сюда, а контроллеры — сюда». Можете делать так, как захотите.

Давайте проведем рефакторинг скрипта, обрабатывающего логи. Его будет легче поддерживать и тестировать, если мы выделим логику парсера в отдельный файл.

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

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

Давайте теперь посмотрим, как импортировать этот файл и использовать новый объект Parser .

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

Так как я вынес в модуль конструктор, то он и вернётся выражением require . Теперь я могу создавать экземпляры Parser и использовать их.

10 Node.js Books That You Should Have on Your Bookshelf

In the world where you can Google and find almost everything, good old books may seem to be a bit out-of-date… Especially technical ones! However, some of them are truly irreplaceable when it comes to all-embracing patterns, covering the basics, or even leading us step by step from the fundamental concepts to some highly-advanced details. Best books on Node.js are not exception.

That’s why we’ve decided to prepare a list of 10 really good Node.js books that can help you in your career as a developer, no matter how experienced you actually are:

If you’re a newbie, you’ll be able to master it, A to Z.

If Node.js is not a novelty for you, some of these books will simply help you structure your knowledge, while the others are going to teach you certain new tricks.

Beginning Node.js by Basarat Ali Syed

Grab this book and let Basarat Ali Syed walk you through the principles. This is one of the easiest way to get started. Among other things, you’re going to learn how to:

set up the whole environment,

develop scalable, full-stack applications,

reuse your code to work more effectively,

test and deploy your app on the Internet.

And you don’t even have to be advanced in JavaScript! Beginning Node.js includes a lot of clear diagrams and simple examples, making the process of learning quite engaging and understandable.

Node.JS Web Development by Dav > If your JavaScript experience is limited only to the front-end, and you want to extend your skills to server-side development — David Herron is going to show you a great and simple alternative to PHP or Python. This is one of the best books to learn Node.js using the Express application framework. Starting with only a rudimentary JS knowledge, you will progress step by step to build striking web apps. This practical guide covers not only the basics but also:

  • mobile-first theming (with Bootstrap),
  • authentication methods (using OAuth),
  • microservice deployment (with Docker),
  • real-time applications (with Socket.IO),
  • unit testing (with Mocha),
  • and functional testing of the app (with CasperJS).

Node.js Design Patterns by Mario Casciaro

This is the book for JS devs who want to dive deep into the Node.js environment, not only to get to know what to do (or when), but also. to understand why. Mario Casciaro provides a bunch of best practises, and a lot of useful tips and tricks, while explaining in details the specifics. You will quickly learn how to:

design and implement JS patterns,

use the components to their full potential,

easily handle the asynchronous code,

prevent many common problems and errors.

Node.js Design Patterns is a must-read for both beginners and experienced developers alike.

Learning Node: Moving to the Server-S > by Shelley Powers

It is definitely not a book for a newbie but it could be really helpful if you already have a substantial knowledge of JS and you want to take your skills to the higher level. It is full of useful programming and deployment examples. And, what is very significant, Shelley Powers updated the second edition with the fairly new Node 6.0 LTS (Long Term Support) release. The book will simply help you:

explore the full functionality of Node.js,

built web apps and HTTP servers using Node modules,

test the apps on fly using Node’s REPL console,

get to know how to use Node.js in the IoT (Internet of Things) and microcomputers.

Getting MEAN with Mongo, Express, Angular, and Node by Simon Holmes

If you want to build dynamic data-driven apps, you should definitely get MEAN… Simon Holmes wrote a complete handbook (based on MongoDB 2, Express 4, Angular 1, and Node.js 4) — one that every budding full-stack developer ought to be familiar with. Go through it, and get some very practical knowledge with ready-to-use examples! The author precisely explained one topic at a time, letting you adopt it before moving on to the other. The book most certainly deserves a place on our Node.js recommendation list because:

it is easy to follow,

it includes the whole package of useful information, also about technologies that can be used with or aside from MEAN stack, such as Git or Bootstrap,

it helps to create fast and responsive applications using only one language — JavaScript. From soup to nuts.

Programming JavaScript Applications Robust Web Architecture with Node, HTML5, and Modern JS Libraries by Eric Elliot

This publication by Eric Elliot is for those of us, who are experienced JS coders willing to become more flexible and versatile in programming. This is one of the best books on Node.js (and HTML5, too) that a JavaScript developer could read. The covered topics include:

adding client-side and server-side functionalities to an app,

best practices of organizing and reusing code,

logging, authentication, and authorization,

testing, integrating, and deploying software updates,

building RESTful APIs,

internationalization in order to expand the apps’ reach.

Node.js for Embedded Systems by Patrick Mulder & Kelsey Breseman

It is a straightforward introduction to Node.js as a platform for Internet of Things. Mulder and Breseman show us some great ways to connect the two words we live in nowadays — analog and digital. Node.js for Embedded Systems will allow you to understand how to:

use JS to program components like microcontrollers and sensors,

run Node.js on Intel Edison or Raspberry Pi,

use Tessel 2 platform to prototype IoT devices,

make use of advanced libraries (such as Johnny-Five) to control machines remotely with Bluetooth,

This guide is simply going to teach you (on a basic to intermediate level), how to talk in JS with different kinds of hardware platforms.

Express in Action. Writing, Building, and Testing Node.js Applications by Evan M. Hahn

Express in Action is a complex, yet clearly-written tutorial on Node.js and Express.js framework but… you need to be fluent in JavaScript first, plus have a basic knowledge on web application design, too. In exchange, you’ll get:

a proper introduction to Node.js,

the key development techniques,

a great piece of information about the libraries and tools,

a glimpse into the code samples.

In the end, you are going to learn how to make use of Express 4 and 5 alpha to build a Node.js app from a scratch, and then take it to the level of testing, hooking it up to a database, and deploying on the Internet.

RESTful Web API Design with Node.JS by Valentin Bojinov

If you need a reliable starting point in RESTful API design with Node.js — don’t hesitate anymore, and dive into this excellent guide written by Valentin Bojinov. The publication is not for first-timers, though. Moreover, it is strongly recommended to be proficient in JavaScript and have some of the basics covered in Node.js as well. This book will frankly take you higher up from this point, teaching you how to:

create server-side RESTful applications which are perfectly scalable,

get rid of the third-party dependencies in testing,

secure the services with NoSQL database integration.

All of it, and much more within the one and only Node.js platform!

Full-Stack JavaScript Development: Develop, Test and Deploy with MongoDB, Express, Angular and Node on AWS by Eric Bush

The handbook to full-stack JavaScript Development by Eric Bush covers all the layers of the classic three tier architecture:

Data Layer (using MongoDB),

Service Layer (within Node.js and Express framework),

Presentation Layer (using Angular).

The author explained step by step, how the abovementioned technologies come together in allowing you to design, build, test, deploy, and then manage RESTful web applications. Flipping through the pages is enough to notice that the book is full of graphics and code snippets which make it easier to understand. Nicely done, Eric!

Учебник Express часть 2: Создание скелета сайта

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

Необходимые знания: Установить среду разработки Node. Просмотреть учебник Express.
Задача: Научиться запускать свои проекты используя Express Application Generator.

Обзор

В этой статье показано, как создать каркас сайта с помощью средства Express Application Generator. Каркас затем можно будет заполнить с помощью путей сайта, шаблонов/представлений и обращений к базе данных. Мы используем это средство для создания основы нашего сайта Local Library. К основе будет добавлен код, необходимый сайту. Создание каркаса чрезвычайно просто — требуется только вызвать генератор в командной строке, указав имя нового проекта, дополнительно можно указать также движок шаблона сайта и генератор CSS.

Далее показано, как вызвать генератор приложений, и даётся небольшое пояснение различных вариантов представлений и CSS. Мы поясним структуру каркаса веб-сайта. В конце мы покажем, как запустить веб-сайт, чтобы убедиться, что он работает.

Замечание: Express Application Generator — не единственный генератор Express-приложений, и созданный проект —не единственный жизнеспособный способ организации ваших файлов и каталогов. Однако созданный сайт имеет модульную структуру, которую легко понять и расширить. О минимальном Express приложении смотрите Hello world example в документации Express.

Применение генератора приложений

Вы уже должны были устанавить express-generator , читая статью установка среды разработки Node. Напомним, что генератор установлен с помощью менеджера пакетов NPM, при выполнении команды:

E xpress-generator имеет ряд параметров, которые можно увидеть, выполнив команду express —help (или express -h):

Команда express создаст проект в текущем каталоге с использованием (устаревшего) движка представления Jade и обычного CSS. Если указать express name , проект будет создан в подкаталоге name текущего каталога.

Можно выбрать движок представления (шаблон), используя — view; параметр — css позволяет выбрать движок для создания CSS.

Заметка: Другие опции ( —hogan , —ejs , —hbs и пр.) для выбора шаблонизатора устарели. Используйте —view (или -v )!

Какой движок представлений следует использовать?

Express-generator дает возможность сконфигурировать несколько популярных движков, включая EJS, Hbs, Pug (Jade), Twig, и Vash, но по умолчанию выбран Jade. Экспресс сразу после установки может поддерживать большое количество и других шаблонизаторов.

Заметка: При желании использовать шаблонизатор, который не поддерживается генератором, просмотрите документацию Using template engines with Express и документацию для нужного шаблонизатора.

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

  • Время до получения результата — если ваша команда уже имела дело с шаблонизатором, то, скоре всего, продуктивнее будет использовать этот шаблонизатор. Если нет, тогда следует учесть все относительные сложности изучения кандидатов в шаблонизаторы.
  • Популярность и активность — проверьте популярность движка, возможно, у него есть активное сообщество. Очень важно иметь поддержку для движка, если у вас возникнут проблемы в течении жизни вебсайта.
  • Стиль — некоторые шаблонизаторы используют особую разметку для отображения вставленного контента внутри «обычного» HTML, а другие строят HTML, используя специальный синтаксис (например, используя отступы или блочные имена).
  • Производительность и время интерпретации.
  • Особенности — следует выбирать движок с учетом таких особенностей:
    • Наследование макета: позволяет определить базовый шаблон и затем наследовать только те части, которые отличаются для конкретной страницы. Это, как правило, лучший подход, чем создание шаблонов путём включения нескольких необходимых компонентов или создания шаблона с нуля каждый раз.
    • Поддержка «Include»: позволяет создавать шаблоны, включая другие шаблоны.
    • Краткий синтаксис управления переменными и циклами.
    • Возможность фильтровать значения переменных на уровне шаблона (например, делать переменные в верхнем регистре или форматировать значение даты).
    • Возможность создавать выходные форматы, отличные от HTML (например, JSON или XML).
    • Поддержка асинхронных операций и потоковой передачи.
    • Возможность использования как на клиенте, так и на сервере. Возможность применения движка шаблона на клиенте позволяет обслуживать данные и выполнять все действия или их большую часть на стороне клиента.

Совет: В интернете множество ресурсов, которые помогут сравнить различные варианты!

Для этого проекта мы используем шаблонизатор Pug (в прошлом назывался Jade) — один из популярнейших Express/JavaScript шаблонизаторов, который поддерживается в Express-generator «из коробки».

Какие шаблонизаторы CSS следует использовать?

Express Application Generator позволяет создавать проекты, настроенные для применения шаблонизаторов CSS: LESS, SASS, Compass, Stylus.

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

Как и в случае с шаблонизаторами сайта, следует применять шаблонизатор, обеспечивающий высокую производительность работы. В этом проекте мы используем обычный CSS (по умолчанию), поскольку простота наших требований к CSS не оправдает применение чего-то более сложного.

Какую базу данных следует использовать?

Сгенерированный код не использует и не содержит в себе какой-либо базы данных. Express может использовать любой движок базы данных, который поддерживается Node (Express не предъявляет каких-либо особых требований к базе данных).

Мы обсудим взаимодействие с базой данных в следующей статье.

Создание проекта

Разрабатывая пример — приложение Local Library, мы построим проект с именем express-locallibrary-tutorial. Используем библиотеку шаблонов Pug, а движок CSS применять не будем.

Выберем место для нового проекта — каталог express-locallibrary-tutorial — и выполним команду:

Будет создан каталог express-locallibrary-tutorial и выведен список созданных внутри каталога проектных файлов .

После списка файлов генератор выведет инструкции для установки зависимостей (указанных в файле package.json) и запуска приложения (инструкции предназначены для Windows; для Linux/Mac OS X они могут слегка отличаться).

Запускаем каркас сайта

Сейчас у нас есть готовый каркас проекта. Сайт пока ничего не делает, но его стоит запустить, чтобы убедиться в его работоспособности.

  1. Прежде всего установим зависимости (команда install запросит все пакеты зависимостей, указанные в файле package.json).
  2. Затем запустим приложение.
    • В Windows используйте команду:
    • В Mac OS X или Linux используйте команду:
  3. Откроем http://localhost:3000/ в браузере. Мы должны увидеть такую страницу:

У нас получилось веб-приложение на базе Express, работающее по адресу localhost:3000.

Заметка: Можно также запустить приложение командой npm start . Переменная DEBUG, указанная в примере, включает логгирование в консоль для дальнейшей отладки. Так, при посещении страницы веб-приложения, вы увидите похожий вывод в консоль:

Обеспечиваем
перезапуск сервера при изменении файлов

Любые изменения, внесенные на веб-сайт Express, не будут отображаться до перезапуска сервера. Остановка (Ctrl-C) и перезапуск сервера каждый раз после внесения изменений быстро становится раздражающей, поэтому стоит автоматизировать перезапуск.

Одно из самых простых средств для этого —
nodemon. Его обычно устанавливают глобально (так как это «инструмент»), но сейчас мы устанавим его и будем применять локально как зависимость разработки, так что любые разработчики проекта получат его автоматически при установке приложения. Выполним следующую команду (предполагаем, что мы находимся в корневом каталоге):

Если вы предпочитаете установить nodemon глобально, не только для этого проекта, надо выполнить команду

В файле package.json проекта появится новый раздел с этой зависимостью (на вашей машине номер версии nodemon может бытьдругим) :

Поскольку nodemon не установлен глобально, его нельзя запустить из командной строки (пока мы не добавим его в путь), но его можно вызвать из сценария NPM, так как NPM знает все об установленных пакетах. Раздел scripts в файле package.json исходно будет содержать одну строку, которая начинается с «start» . Обновите его, поставив запятую в конце строки, и добавьте строку «devstart», показанную ниже:

Теперь можно запустить сервер почти так же, как и ранее, но командой npm run devstart:

Заметка: Сейчас после изменения любого файла проекта сервер будет перезапускаться (или можно самостоятельно перезапустить его, введя rs в командной строке). Вам все равно придется обновить страницу в браузере .

Теперь мы должны выполнять команду » npm run

Учебник Express часть 2: Создание скелета сайта

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

Необходимые знания: Установить среду разработки Node. Просмотреть учебник Express.
Задача: Научиться запускать свои проекты используя Express Application Generator.

Обзор

В этой статье показано, как создать каркас сайта с помощью средства Express Application Generator. Каркас затем можно будет заполнить с помощью путей сайта, шаблонов/представлений и обращений к базе данных. Мы используем это средство для создания основы нашего сайта Local Library. К основе будет добавлен код, необходимый сайту. Создание каркаса чрезвычайно просто — требуется только вызвать генератор в командной строке, указав имя нового проекта, дополнительно можно указать также движок шаблона сайта и генератор CSS.

Далее показано, как вызвать генератор приложений, и даётся небольшое пояснение различных вариантов представлений и CSS. Мы поясним структуру каркаса веб-сайта. В конце мы покажем, как запустить веб-сайт, чтобы убедиться, что он работает.

Замечание: Express Application Generator — не единственный генератор Express-приложений, и созданный проект —не единственный жизнеспособный способ организации ваших файлов и каталогов. Однако созданный сайт имеет модульную структуру, которую легко понять и расширить. О минимальном Express приложении смотрите Hello world example в документации Express.

Применение генератора приложений

Вы уже должны были устанавить express-generator , читая статью установка среды разработки Node. Напомним, что генератор установлен с помощью менеджера пакетов NPM, при выполнении команды:

E xpress-generator имеет ряд параметров, которые можно увидеть, выполнив команду express —help (или express -h):

Команда express создаст проект в текущем каталоге с использованием (устаревшего) движка представления Jade и обычного CSS. Если указать express name , проект будет создан в подкаталоге name текущего каталога.

Можно выбрать движок представления (шаблон), используя — view; параметр — css позволяет выбрать движок для создания CSS.

Заметка: Другие опции ( —hogan , —ejs , —hbs и пр.) для выбора шаблонизатора устарели. Используйте —view (или -v )!

Какой движок представлений следует использовать?

Express-generator дает возможность сконфигурировать несколько популярных движков, включая EJS, Hbs, Pug (Jade), Twig, и Vash, но по умолчанию выбран Jade. Экспресс сразу после установки может поддерживать большое количество и других шаблонизаторов.

Заметка: При желании использовать шаблонизатор, который не поддерживается генератором, просмотрите документацию Using template engines with Express и документацию для нужного шаблонизатора.

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

  • Время до получения результата — если ваша команда уже имела дело с шаблонизатором, то, скоре всего, продуктивнее будет использовать этот шаблонизатор. Если нет, тогда следует учесть все относительные сложности изучения кандидатов в шаблонизаторы.
  • Популярность и активность — проверьте популярность движка, возможно, у него есть активное сообщество. Очень важно иметь поддержку для движка, если у вас возникнут проблемы в течении жизни вебсайта.
  • Стиль — некоторые шаблонизаторы используют особую разметку для отображения вставленного контента внутри «обычного» HTML, а другие строят HTML, используя специальный синтаксис (например, используя отступы или блочные имена).
  • Производительность и время интерпретации.
  • Особенности — следует выбирать движок с учетом таких особенностей:
    • Наследование макета: позволяет определить базовый шаблон и затем наследовать только те части, которые отличаются для конкретной страницы. Это, как правило, лучший подход, чем создание шаблонов путём включения нескольких необходимых компонентов или создания шаблона с нуля каждый раз.
    • Поддержка «Include»: позволяет создавать шаблоны, включая другие шаблоны.
    • Краткий синтаксис управления переменными и циклами.
    • Возможность фильтровать значения переменных на уровне шаблона (например, делать переменные в верхнем регистре или форматировать значение даты).
    • Возможность создавать выходные форматы, отличные от HTML (например, JSON или XML).
    • Поддержка асинхронных операций и потоковой передачи.
    • Возможность использования как на клиенте, так и на сервере. Возможность применения движка шаблона на клиенте позволяет обслуживать данные и выполнять все действия или их большую часть на стороне клиента.

Совет: В интернете множество ресурсов, которые помогут сравнить различные варианты!

Для этого проекта мы используем шаблонизатор Pug (в прошлом назывался Jade) — один из популярнейших Express/JavaScript шаблонизаторов, который поддерживается в Express-generator «из коробки».

Какие шаблонизаторы CSS следует использовать?

Express Application Generator позволяет создавать проекты, настроенные для применения шаблонизаторов CSS: LESS, SASS, Compass, Stylus.

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

Как и в случае с шаблонизаторами сайта, следует применять шаблонизатор, обеспечивающий высокую производительность работы. В этом проекте мы используем обычный CSS (по умолчанию), поскольку простота наших требований к CSS не оправдает применение чего-то более сложного.

Какую базу данных следует использовать?

Сгенерированный код не использует и не содержит в себе какой-либо базы данных. Express может использовать любой движок базы данных, который поддерживается Node (Express не предъявляет каких-либо особых требований к базе данных).

Мы обсудим взаимодействие с базой данных в следующей статье.

Создание проекта

Разрабатывая пример — приложение Local Library, мы построим проект с именем express-locallibrary-tutorial. Используем библиотеку шаблонов Pug, а движок CSS применять не будем.

Выберем место для нового проекта — каталог express-locallibrary-tutorial — и выполним команду:

Будет создан каталог express-locallibrary-tutorial и выведен список созданных внутри каталога проектных файлов .

После списка файлов генератор выведет инструкции для установки зависимостей (указанных в файле package.json) и запуска приложения (инструкции предназначены для Windows; для Linux/Mac OS X они могут слегка отличаться).

Запускаем каркас сайта

Сейчас у нас есть готовый каркас проекта. Сайт пока ничего не делает, но его стоит запустить, чтобы убедиться в его работоспособности.

  1. Прежде всего установим зависимости (команда install запросит все пакеты зависимостей, указанные в файле package.json).
  2. Затем запустим приложение.
    • В Windows используйте команду:
    • В Mac OS X или Linux используйте команду:
  3. Откроем http://localhost:3000/ в браузере. Мы должны увидеть такую страницу:

У нас получилось веб-приложение на базе Express, работающее по адресу localhost:3000.

Заметка: Можно также запустить приложение командой npm start . Переменная DEBUG, указанная в примере, включает логгирование в консоль для дальнейшей отладки. Так, при посещении страницы веб-приложения, вы увидите похожий вывод в консоль:

Обеспечиваем
перезапуск сервера при изменении файлов

Любые изменения, внесенные на веб-сайт Express, не будут отображаться до перезапуска сервера. Остановка (Ctrl-C) и перезапуск сервера каждый раз после внесения изменений быстро становится раздражающей, поэтому стоит автоматизировать перезапуск.

Одно из самых простых средств для этого —
nodemon. Его обычно устанавливают глобально (так как это «инструмент»), но сейчас мы устанавим его и будем применять локально как зависимость разработки, так что любые разработчики проекта получат его автоматически при установке приложения. Выполним следующую команду (предполагаем, что мы находимся в корневом каталоге):

Если вы предпочитаете установить nodemon глобально, не только для этого проекта, надо выполнить команду

В файле package.json проекта появится новый раздел с этой зависимостью (на вашей машине номер версии nodemon может бытьдругим) :

Поскольку nodemon не установлен глобально, его нельзя запустить из командной строки (пока мы не добавим его в путь), но его можно вызвать из сценария NPM, так как NPM знает все об установленных пакетах. Раздел scripts в файле package.json исходно будет содержать одну строку, которая начинается с «start» . Обновите его, поставив запятую в конце строки, и добавьте строку «devstart», показанную ниже:

Теперь можно запустить сервер почти так же, как и ранее, но командой npm run devstart:

Заметка: Сейчас после изменения любого файла проекта сервер будет перезапускаться (или можно самостоятельно перезапустить его, введя rs в командной строке). Вам все равно придется обновить страницу в браузере .

Теперь мы должны выполнять команду » npm run

Добавить комментарий