Слайд 3Основы Node.js
Node.js представляет среду выполнения кода на JavaScript, которая построена на основе
движка JavaScript Chrome V8, который позволяет транслировать вызовы на языке JavaScript в машинный код.
Node.js прежде всего предназначен для создания серверных приложений на языке JavaScript, хотя также существуют проекты по написанию десктопных приложений (к примеру, фреймворк Electron, разработанный GitHub) и даже по созданию кода для микроконтроллеров.
Но прежде всего мы говорим о Node.js, как о платформе для создания веб-приложений.
Для разработки под Node.js достаточно простейшего текстового редактора.
Слайд 4Инструмент REPL
Для загрузки перейдите на официальный сайт https://nodejs.org/en/.
После установки на компьютер Node.js
нам становится доступным инструмент REPL.
REPL (Read Eval Print Loop) представляет возможность запуска выражений на языке JavaScript в командной строке (ОС Windows) или терминале (OS X, Linux).
При запуске командной строки (cmd) или терминала можно ввести команду node.
После ввода этой команды можно выполнять различные выражения на JavaScript.
Есть несколько команд, которые позволят управлять данным режимом. К примеру, команда «.exit» позволит выйти из режима REPL.
Слайд 5Инструмент REPL
Пример:
При ошибке в коде REPL укажет об этом:
Слайд 6Инструмент REPL
Выполнение файла
Вместо того чтобы вводить весь код напрямую в консоль, удобнее
вынести его во внешний файл.
Например, создадим файл app.js с кодом:
Он просто выводит текст в консоль. Выполним его командой node:
Слайд 7Модули
Node.js использует модульную систему.
Вся встроенная функциональность разбита на отдельные пакеты или
модули.
Модуль представляет блок кода, который может использоваться в других модулях.
При необходимости мы можем подключать нужные нам модули.
В документации (https://nodejs.org/api/) можно узнать о встроенных модулях Node.js и их функциональности.
Слайд 8Модули
Для загрузки модулей применяется функция require().
К примеру, для получения и обработки
запроса был необходим модуль http.
Создадим файл app.js:
Слайд 9Модули
Подобным образом мы можем загружать и использовать другие встроенные модули.
Например, используем
модуль os, который предоставляет информацию об окружении и ОС.
Слайд 10Пользовательские модули
При необходимости можно создавать свои модули.
Но в отличие от встроенных
модулей для подключения своих модулей надо передать в функцию require относительный путь с именем файла.
К примеру, если файл «app1.js» располагается рядом с запускаемым файлом:
Для его исполнения можно написать:
Слайд 11Пользовательские модули
Передача данных из модуля
Если мы описываем переменные или функции внутри модуля,
то извне они недоступны.
Чтобы они стали доступны, необходимо определить их в объекте module.exports.
Объект module.exports – это то, что возвращает функция require() при получении модуля.
Объект module представляет ссылку на текущий модуль, а его свойство exports определяет все свойства и методы модуля, которые могут быть экспортированы и использованы в других модулях.
Слайд 12Пользовательские модули
Например, создан файл модуля moduleTime.js:
Подключим его в файле app.js:
Сразу стоит отметить,
что подключаемые модули кэшируются. Если несколько раз получить модуль в разные константы, то все они будут указывать на один и тот же объект.
Слайд 13Пользовательские модули
Передача конструктора из модуля
Кроме определения простейших функций или свойств в модуле
могут определяться сложные объекты или функции конструкторов.
Пример:
Создадим файл модуля user.js:
Слайд 14Пользовательские модули
Весь модуль user указывает на определенную функцию конструктора.
Файл app.js:
Слайд 15Структура модулей
Нередко модули приложения образуют какие-то отдельные наборы или области. Такие наборы
модулей лучше помещать в отдельные каталоги.
Например, у нас есть в каталоге приложения подкаталог welcome, а в нем три файла: index.js, morning.js, evening.js. В итоге общая структура проекта:
Слайд 16Структура модулей
Файл morning.js:
Файл evening.js:
Файл index.js:
Слайд 17Структура модулей
Теперь используем модуль index.js в файле app.js:
Так как файла welcome.js нет, но
есть каталог welcome, который содержит файл с именем index.js, то можно обращаться к модулю по имени каталога.
Слайд 18Объект global и глобальные переменные
Node.js предоставляет специальный объект global, который предоставляет доступ
к глобальным переменным и функциям. Примерным аналогом данного объекта в JavaScript является объект window.
Для примера создадим следующий модуль greeting.js:
Слайд 19Объект global и глобальные переменные
Определим файл приложения app.js:
Здесь устанавливаем глобальную переменную name, которую
мы получаем в модуле greeting.js и также выводим на консоль глобальную переменную date.
Слайд 20Передача параметров приложению
При запуске приложения из терминала/командной строки можно передавать ему параметры.
Для получения параметров в коде приложения применяется массив process.argv.
Первый элемент этого массива всегда указывает на путь к файлу node.exe, который вызывает приложение.
Второй элемент массив всегда указывает на путь к файлу приложения, который выполняется.
Слайд 21Передача параметров приложению
К примеру, определим следующий файл app.js:
Слайд 22Передача параметров приложению
Запуск приложения без параметров и с ними:
Слайд 23Установка модулей
Кроме встроенных и пользовательских модулей Node.js существует огромное количество различных библиотек,
фреймворков и утилит, созданных сторонними производителями и которые можно использовать в проекте, например, express, grunt, gulp и т.д.
Чтобы удобнее было работать со всеми сторонними решениями, они распространяются в виде пакетов.
Для автоматизации установки и обновления пакетов в Node.js используется пакетный менеджер NPM (Node Package Manager), который устанавливается вместе с Node.js. Но можно обновить установленную версию до последней.
Слайд 24Установка модулей
Можно обновить установленную версию NPM до последней:
npm install npm@latest -g
Может
потребоваться запустить командную строку от имени администратора.
Чтобы узнать текущую версию NPM:
npm -v
Слайд 25Установка модулей
Файл package.json
Для более удобного управления конфигурацией и пакетами приложения в NPM
применяется файл конфигурации package.json.
К примеру, у нас имеется каталог проекта modulesapp. Добавим в него файл package.json:
Здесь определены только две секции: имя проекта – modulesapp и его версия - 1.0.0. Это минимально необходимое определение файла package.json.
Слайд 26Установка модулей
Далее для примера установим в проект пакет Express.
Для установки функциональности
Express в проект вначале перейдем в каталог проекта, затем введем команду:
npm install express
Слайд 27Установка модулей
После установки Express в папке проекта modulesapp появится подпапка node_modules, в которой
будут храниться все установленные внешние модули.
В файл package.json также добавится информация о данном модуле:
Информация обо всех добавляемых пакетах, которые используются при работе приложения, добавляется в секцию dependencies.
Слайд 28Установка модулей
Можно устанавливать множество пакетов одной командой.
В этом случае мы можем
определить все необходимые пакеты в файле package.json и потом одной командой их установить. К примеру:
Затем для загрузки всех пакетов выполнить команду
npm install
Слайд 29Установка модулей
Для удаления пакетов используется команда npm uninstall. Например:
npm uninstall express
Если нам надо
удалить не один пакет, а несколько, то мы можем удалить их определение из файла package.json и ввести команду npm install, и удаленые из package.js пакеты также будут удалены из папки node_modules.
Слайд 30Команды NPM
NPM позволяет определять в файле package.json команды, которые выполняют определенные действия.
Например, определим следующий файл app.js:
Слайд 31Команды NPM
Определим следующий файл package.json:
Здесь добавлена секция scripts, которая определяет две команды.
Названия
и количество команд могут быть произвольными.
Слайд 32Команды NPM
Но надо учитывать, что есть некоторые предопределенные названия для команд, например,
start, test, run и т.д.
И для их выполнения в терминале/командной строке надо выполнить команду в каталоге приложения:
npm [название_команды]
Команды с остальными названиями (например, «dev») запускаются так:
npm run [название_команды]
Слайд 33Команды NPM
Например, последовательно выполним обе команды:
Слайд 34Асинхронность в Node.js
Асинхронность представляет возможность одновременно выполнять сразу несколько задач.
Например, допустим
в файле приложения app.js у нас расположен следующий синхронный код:
Слайд 35Асинхронность в Node.js
Для рассмотрения асинхронности изменим код файла app.js следующим образом:
Теперь вывод сообщения «Обработка
данных…» будет выполняться асинхронно с остальным кодом.
Для того используется функция setTimeout().
Слайд 36Асинхронность в Node.js
Результат:
Несмотря на то, что в setTimeout передается промежуток 0, фактическое
выполнение функции display завершается после всех остальных функций, которые определены в программе. В итоге исполнение кода на функции display не блокируется, а идет дальше.
Такое происходит из-за того, что функции обратного вызова в асинхронных функциях помещаются в специальную очередь, и начинают выполняться после того, как все остальные синхронные вызовы в приложении завершат свою работу.
Слайд 37События
Подавляющее большинство функционала Node.js применяет асинхронную событийную архитектуру, которая использует специальные объекты
– эмиттеры для генерации различных событий, которые обрабатываются специальными функциями – обработчиками или слушателями событий.
Весь необходимый функционал сосредоточен в модуле events.
Объекты, которые генерируют события, – экземпляры класса EventEmitter.
С помощью функции eventEmitter.on() к определенному событию по имени цепляется функция обработчика. Причем для одного события можно указать множество обработчиков.
Слайд 38События
Для примера определим следующий файл app.js:
Для генерации события выполняется функция emitter.emit().
Слайд 39События
Передача параметров событию
При вызове события в качестве второго параметра в функцию emit
можно передавать некоторый объект, который передается в функцию обработчика события:
Слайд 40События
Наследование от EventEmitter
В приложении мы можем оперировать сложными объектами, для которых также
можно определять события, но для этого их надо связать с объектом EventEmitter:
Слайд 41Работа с файловой системой. Модуль fs
Чтение из файла
Допустим, в одной папке с
файлом приложения app.js расположен текстовый файл hello.txt с простейшим текстом, например «Hello World».
Для чтения файла в синхронном варианте применяется функция fs.readFileSync():
На выходе получаем считанный текст.
Слайд 42Работа с файловой системой. Модуль fs
Для асинхронного чтения файла применяется функция fs.readFile():
Третий
параметр здесь – функция обратного вызова, которая выполняется после завершения чтения:
Первый параметр этой функции – информация об ошибке, второй – считанные данные.
Слайд 43Работа с файловой системой. Модуль fs
Для чтения файла определим в файле app.js
следующий код:
Слайд 44Работа с файловой системой. Модуль fs
Запись файла
Для записи файла в синхронном варианте
используется функция fs.writeFileSync(), которая в качестве параметра принимает путь к файлу и записываемые данные:
Также для записи файла можно использовать асинхронную функцию fs.writeFile():
В качестве вспомогательного параметра в функцию может передаваться функция обратного вызова, которая выполняется после завершения записи.
Слайд 45Работа с файловой системой. Модуль fs
Пример:
Данные методы полностью перезаписывают файл.
Если надо
осуществить дозапись, то применяются методы fs.appendFile() / fs.appendFileSync().
Слайд 46Работа с файловой системой. Модуль fs
Удаление файла
Для удаления файла в синхронном варианте
используется функция fs.unlinkSync(), которая в качестве параметра принимает путь к удаляемому файлу:
Также для удаления файла можно использовать асинхронную функцию fs.unlink(), которая принимает путь к файлу и функцию, вызываемую при завершении удаления.
Слайд 47Потоки данных
Объект Stream представляет поток данных.
Потоки бывают различных типов, среди которых
можно выделить потоки для чтения и потоки для записи.
К примеру, при создании сервера используются потоки:
Параметры request и response, которые передаются в функцию, и с помощью которых мы можем получать данные о запросе и управлять ответом, как раз представляют собой потоки для чтения и для записи соответственно.
Слайд 48Потоки данных
Используя потоки чтения и записи, можно считывать и записывать информацию в
файл.
Поток записи
Для создания потока для записи применяется метод fs.createWriteStream(), в который передается название файла.
Запись данных производится с помощью метода write(), в который передаются данные.
Для окончания записи вызывается метод end().
Слайд 49Потоки данных
Поток чтения
Для создания потока для чтения используется метод fs.createReadStream(), в который
также передается название файла.
Сам поток разбивается на ряд кусков или чанков (chunk).
При считывании каждого такого куска, «автоматически» возникает событие data.
Слайд 51Канал Pipe
Pipe – это канал, который связывает поток для чтения и поток
для записи и позволяет сразу считать из потока чтения в поток записи.
Рассмотрим пример с копированием данных из одного файла в другой.
Эта задача является довольно распространенной, и в этом случае каналы (pipe) позволяют нам сократить объем кода.
Слайд 52Канал Pipe
Скопируем содержимое файла hello.txt в новый файл some.txt:
У потока чтения вызывается метод
pipe(), в который передается поток для записи.
Слайд 53Клиент-серверная архитектура приложения
Протокол HTTP предоставляет набор методов для указания целей запроса, отправляемого
серверу.
Эти методы основаны на дисциплине ссылок, где для указания ресурса, к которому должен быть применен данный метод, используется универсальный идентификатор ресурсов (Universal Resource Identifier, URI) в виде местонахождения ресурса (Universal Resource Locator, URL) или в виде его универсального имени (Universal Resource Name, URN ).
Протокол HTTP реализует принцип запрос/ответ.
Слайд 54Клиент-серверная архитектура приложения
Запрашивающая программа–клиент инициирует взаимодействие с отвечающей программой–сервером, и посылает запрос,
содержащий:
метод доступа;
адрес URL;
версию протокола;
сообщение с информацией о типе передаваемых данных, информацией о клиенте, пославшем запрос, и, возможно, с содержательной частью (телом) сообщения.
Ответ сервера содержит:
строку состояния, в которую входит версия протокола и код возврата (успех или ошибка);
сообщение, в которое входит информация сервера, метаинформация и тело сообщения.
Соединение, как правило, открывает клиент, а сервер после отправки ответа инициирует его разрыв.
Слайд 55Создание сервера
Для работы с сервером и протоколом HTTP в Node.js используется модуль
http.
Чтобы создать сервер, следует вызвать метод http.createServer():
Данный метод возвращает объект http.Server.
Чтобы сервер мог прослушивать и обрабатывать входящие подключения, у объекта сервера необходимо вызвать метод listen().
Слайд 56Создание сервера
Для обработки подключений можно передать особую функцию:
Эта функция принимает два параметра:
request
– хранит информацию о запросе;
response – управляет отправкой ответа.
Слайд 57Создание сервера
Request
Параметр request позволяет получить информацию о запросе и представляет объект http.IncomingMessage.
Отметим некоторые основные свойства этого объекта:
headers: возвращает заголовки запроса;
method: тип запроса (GET, POST, DELETE, PUT);
url: представляет запрошенный адрес.
Слайд 58Создание сервера
Например, определим следующий файл app.js:
Запустим его и обратимся в
браузере по
адресу
http://localhost:3000/index.html:
Слайд 59Создание сервера
Response
Параметр response управляет отправкой ответа и представляет объект http.ServerResponse.
Среди его
функциональности можно выделить следующие методы:
statusCode: устанавливает статусный код ответа;
statusMessage: устанавливает сообщение, отправляемое вместе со статусным кодом;
setHeader(name, value): добавляет в ответ один заголовок;
write: пишет в поток ответа некоторое содержимое;
writeHead: добавляет в ответ статусный код и набор заголовков;
end: сигнализирует серверу, что заголовки и тело ответа установлены, в итоге ответ отсылается клиента. Данный метод должен вызываться в каждом запросе.
Слайд 60Создание сервера
Например, изменим файл app.js следующим образом:
Слайд 61Маршрутизация
Node.js не имеет встроенной системы маршрутизации адресов запросов к серверу.
Обычно она
реализуется с помощью специальных фреймворков типа Express.
Однако если необходимо разграничить простейшую обработку небольшого количества маршрутов, то вполне можно использовать для этого свойство url объекта request.
Слайд 63Маршрутизация
В данном случае обрабатываются три маршрута и неправильный ввод маршрута.
Слайд 64Переадресация
Переадресация предполагает отправку статусного кода:
301 (постоянная переадресация)
302 (временная переадресация)
А также
заголовка Location, который указывает на новый адрес.
Слайд 66Отправка файлов
Отправка статических файлов – частая задача в работе веб-приложения.
Пусть в
каталоге проекта у нас будут три файла:
index.html about.html
Наша задача будет заключаться в том, чтобы отправить их содержимое пользователю.
Слайд 67Первый способ отправки файлов
Для этого может применяться метод fs.createReadStream().
Затем с помощью метода
pipe() мы можем связать считанные файлы с потоком записи, то есть объектом response.
Слайд 68Первый способ отправки файлов
Файл app.js :
Слайд 69Первый способ отправки файлов
Метод fs.createReadStream() создает поток для чтения – объект fs.ReadStream.
Для
получения данных из потока вызывается метод pipe(), в который передается объект интерфейса stream.Writable или поток для записи (объект http.ServerResponse).
Запустим приложение и в браузере обратимся по адресу:
Слайд 70Первый способ отправки файлов
В данном случае отправляются файлы html, но подобным образом
можно отправлять разные файлы.
Например, создадим новый файл styles.css со следующим содержимым:
Добавим стили на станице index.html в :
И затем обратимся к index.html:
Слайд 71Второй способ отправки файлов
Второй способ представляет чтение данных с помощью функции fs.readFile()
и отправка с помощью метода response.end():
Слайд 72Шаблоны
Вместо статичного содержимого можно применять шаблоны, вместо которых в файл будет вставляться
какой-то определенный текст.
Например, изменим файл index.html следующим образом:
Вместо конкретного содержимого здесь определены прейсхолдеры {header} и {message}, вместо которых может вставляться любой текст.