035.1 Урок 1
Сертифікат: |
Основи веброзробки |
---|---|
Версія: |
1.0 |
Розділ: |
035 Серверне програмування Node.js |
Тема: |
035.1 Основи Node.js |
Урок: |
1 з 1 |
Вступ
Node.js — це середовище виконання JavaScript, яке запускає код JavaScript на вебсерверах, так званому веб backend (серверній стороні), замість використання другої мови, як-от Python або Ruby, для програм на стороні сервера. Мова JavaScript вже використовується в сучасному інтерфейсі вебзастосунків, взаємодіючи з HTML і CSS інтерфейсу, з яким користувач взаємодіє з браузера. Використання Node.js у тандемі з JavaScript у браузері дає можливість використовувати лише одну мову програмування для всього застосунку.
Основною причиною виникнення Node.js є те, як він обробляє декілька одночасних підключень на серверній частині. Одним із найпоширеніших способів, яким сервер вебзастосунків обробляє з’єднання, є виконання кількох процесів. Коли ви відкриваєте на комп’ютері програму, запускається процес, який використовує багато ресурсів. Тепер подумайте про те, що відбувається, коли тисячі користувачів виконують однакові дії у великому вебзастосунку.
Node.js уникає цієї проблеми, використовуючи дизайн, який називається цикл події, який є внутрішнім циклом, що постійно перевіряє наявність вхідних завдань, які потрібно обчислити. Завдяки широкому використанню JavaScript та розповсюдженню вебтехнологій, Node.js отримав величезне поширення як у малих, так і у великих застосунках. Існують інші характеристики, які також допомогли поширенню Node.js, наприклад, асинхронна й неблокуюча обробка введення/виводу (I/O), що пояснюється далі в цьому уроці.
Середовище Node.js використовує механізм JavaScript для інтерпретації та виконання коду JavaScript на стороні сервера або на настільному комп’ютері. У цих умовах код JavaScript, який пише програміст, аналізується і компілюється безпосередньо перед виконанням машинних інструкцій, згенерованих оригінальним кодом JavaScript.
Продовжуючи вивчати ці уроки про Node.js, ви можете помітити, що JavaScript Node.js не зовсім такий самий, як той, який працює у браузері (який відповідає https://www.ecma-international.org/publications-and-standards/standards/ [специфікації ECMAScript]), але дуже схожий.
Початок роботи
Цей розділ і наступні приклади припускають, що Node.js вже встановлено у вашій операційній системі Linux і що користувач уже має базові навички, такі як виконання команд в терміналі.
Щоб запустити наведені нижче приклади, створіть робочий каталог під назвою node_examples
. Відкрийте термінал і введіть node
. Якщо ви правильно встановили Node.js, він відобразить підказку >
, де ви можете інтерактивно перевірити команди JavaScript. Такий тип середовища називається REPL, що означає “read, evaluate, print, and loop”. Введіть наступні вхідні дані (або деякі інші оператори JavaScript) у командному рядку після >
. Натискайте клавішу Enter після кожного рядка, і середовище REPL поверне результати своїх дій:
> let array = ['a', 'b', 'c', 'd']; undefined > array.map( (element, index) => (`Element: ${element} at index: ${index}`)); [ 'Element: a at index: 0', 'Element: b at index: 1', 'Element: c at index: 2', 'Element: d at index: 3' ] >
Фрагмент був написаний з використанням синтаксису ES6, який пропонує функцію map для ітерації по масиву та друку результатів за допомогою шаблонів рядків. Ви можете написати майже будь-яку дійсну команду. Щоб вийти з терміналу Node.js, введіть .exit
, не забувши вказати початкову крапку.
Для роботи з довшими сценаріями і модулями зручніше використовувати текстовий редактор, наприклад VS Code, Emacs або Vim. Ви можете зберегти два щойно показані рядки коду (з невеликими змінами) у файлі під назвою start.js
:
let array = ['a', 'b', 'c', 'd'];
array.map( (element, index) => ( console.log(`Element: ${element} at index: ${index}`)));
Потім ви можете запустити сценарій з оболонки, щоб отримати ті ж результати, що й раніше:
$ node ./start.js Element: a at index: 0 Element: b at index: 1 Element: c at index: 2 Element: d at index: 3
Перш ніж зануритися в інший код, зробимо огляд роботи Node.js, використовуючи його однопотокове середовище виконання та цикл подій.
Цикл подій та єдиний потік
Важко сказати, скільки часу знадобиться вашій Node.js програмі для обробки запиту. Деякі запити можуть бути короткими, можливо, просто перебирають змінні в пам’яті та повертають їх, тоді як інші можуть вимагати трудомістких дій, таких як відкриття файлу в системі або надсилання запиту до бази даних і очікування результатів. Як Node.js справляється із цією невизначеністю? Відповіддю є цикл подій.
Уявіть собі шеф-кухаря, який виконує кілька завдань. Випікання пирога – це одне з завдань, яке вимагає багато часу, щоб духовка його приготувала. Шеф-кухар не залишається там, чекаючи, поки пиріг буде готовий, щоб потім приготувати каву. Натомість, поки духовка випікає пиріг, кухар паралельно готує каву та виконує інші завдання. Але він завжди перевіряє, чи не настав час переключитися на конкретне завдання (приготувати каву) чи дістати пиріг з духовки.
Цикл подій схожий на шеф-кухаря, який постійно в курсі того, що відбувається навколо. У Node.js “event-checker” завжди перевіряє операції, які завершилися або очікують на обробку движком JavaScript.
Використовуючи цей підхід, асинхронна та тривала операція не блокує інші швидкі операції, які відбуваються після неї. Це тому, що механізм циклу подій весь час перевіряє, чи вже виконано це довге завдання, наприклад операція введення-виводу. Якщо ні, Node.js може продовжувати обробляти інші завдання. Після завершення фонового завдання результати повертаються, і застосунок поверх Node.js може використовувати функцію тригера (callback - зворотний виклик) для подальшої обробки результату.
Оскільки Node.js уникає використання кількох потоків, на відміну від інших середовищ, його називають однопоточним середовищем, і тому підхід без блокування є надзвичайно важливим. Ось чому Node.js використовує цикл подій. Однак Node.js для завдань із інтенсивними обчисленнями не є найкращим інструментом: існують інші мови програмування та середовища, які ефективніше вирішують ці проблеми.
У наступних розділах ми детальніше розглянемо функції зворотного виклику. Наразі важливо зрозуміти, що функції зворотного виклику є тригерами, які виконуються після завершення попередньо визначеної операції.
Модулі
Рекомендується розбивати складну функціональність і великі фрагменти коду на менші частини. Такий поділ на модулі допомагає краще організувати базу коду, абстрагуватися від конкретних реалізацій та уникнути складних інженерних проблем. Щоб задовольнити ці потреби, програмісти пакують блоки вихідного коду для використання іншими внутрішніми або зовнішніми частинами коду.
Розглянемо приклад програми, яка обчислює об’єм кулі. Відкрийте текстовий редактор і створіть файл під назвою volumeCalculator.js
, який містить наступний код JavaScript:
const sphereVol = (radius) => {
return 4 / 3 * Math.PI * radius
}
console.log(`Куля з радіусом 3 має об'єм ${sphereVol(3)}.`);
console.log(`Куля з радіусом 6 має об'єм ${sphereVol(6)}.`);
Тепер запустіть файл за допомогою Node:
$ node volumeCalculator.js Куля з радіусом 3 має об'єм 113.09733552923254. Куля з радіусом 6 має об'єм 904.7786842338603.
Тут була використана проста функція для обчислення об’єму кулі на основі її радіуса. Уявіть собі, що нам також потрібно обчислити об’єм циліндра, конуса тощо: ми швидко помічаємо, що ці специфічні функції потрібно додати до файлу volumeCalculator.js
, який може стати величезною колекцією функцій. Щоб краще організувати структуру, ми можемо використовувати ідею модулів як пакетів виділеного коду.
Для цього створіть окремий файл під назвою polyhedrons.js
:
const coneVol = (radius, height) => {
return 1 / 3 * Math.PI * Math.pow(radius, 2) * height;
}
const cylinderVol = (radius, height) => {
return Math.PI * Math.pow(radius, 2) * height;
}
const sphereVol = (radius) => {
return 4 / 3 * Math.PI * Math.pow(radius, 3);
}
module.exports = {
coneVol,
cylinderVol,
sphereVol
}
Тепер у файлі volumeCalculator.js
видаліть старий код і замініть його цим фрагментом:
const polyhedrons = require('./polyhedrons.js');
console.log(`Куля з радіусом 3 має об'єм ${polyhedrons.sphereVol(3)}.`);
console.log(`Циліндр з радіусом 3 і висотою 5 має має об'єм ${polyhedrons.cylinderVol(3, 5)}.`);
console.log(`Конус з радіусом 3 і висотою 5 має об'єм ${polyhedrons.coneVol(3, 5)} volume.`);
А потім запустіть файл з цим ім’ям в середовищі Node.js:
$ node volumeCalculator.js Куля з радіусом 3 має об'єм 113.09733552923254. Циліндр з радіусом 3 і висотою 5 має об'єм 141.3716694115407. Конус з радіусом 3 і висотою 5 має об'єм 47.12388980384689.
У середовищі Node.js кожен файл вихідного коду вважається модулем, але слово “module” у Node.js вказує на пакунок коду, загорнутого як у попередньому прикладі. Використовуючи модулі, ми відокремили функції обчислення об’єму від основного файлу volumeCalculator.js
, таким чином зменшивши його розмір та полегшивши застосування модульних тестів, які є гарною практикою при розробці реальних застосунків.
Тепер, коли ми знаємо, як модулі використовуються в Node.js, ми можемо використовувати один з найважливіших інструментів: менеджер пакунків Node (NPM, Node Package Manager).
Однією з основних завдань NPM є керування, завантаження та встановлення зовнішніх модулів у проєкт або в операційну систему. Ви можете ініціалізувати репозиторій node за допомогою команди npm init
.
NPM задасть запитання за замовчуванням про назву вашого репозиторію, версію, опис тощо. Ви можете обійти ці кроки за допомогою npm init --yes
, і команда автоматично згенерує файл package.json
, який описує властивості вашого проєкту/модуля.
Відкрийте файл package.json
у своєму улюбленому текстовому редакторі, і ви побачите файл JSON, що містить такі властивості, як ключові слова, команди сценарію для використання з NPM, ім’я тощо.
Однією із цих властивостей є залежності, які встановлені у вашому локальному репозиторії. NPM додасть ім’я та версію цих залежностей у package.json
разом із package-lock.json
, іншим файлом, який використовується як резервний файл NPM у разі, якщо package.json
дає збій.
Введіть наступне у своєму терміналі:
$ npm i dayjs
Прапор i
є скороченням для аргументу install
. Якщо ви підключені до Інтернету, NPM шукатиме модуль з назвою dayjs
у віддаленому репозиторії Node.js, завантажить модуль та встановить його локально. NPM також додасть цю залежність до ваших файлів package.json
і package-lock.json
. Тепер ви можете побачити, що є папка під назвою node_modules
, яка містить встановлений модуль разом з іншими модулями, якщо вони потрібні. Каталог node_modules
містить фактичний код, який буде використано під час імпортування та виклику бібліотеки. Однак ця папка не зберігається в системах керування версіями, які використовують Git, оскільки файл package.json
містить усі залежності, що використовуються. Інший користувач може взяти файл package.json
і просто запустити npm install
на своїй власній машині, де NPM створить папку node_modules
з усіма залежностями в package.json
, таким чином уникаючи контролю версій для тисячі файлів, доступних у репозиторії NPM.
Тепер, коли модуль dayjs
встановлено в локальному каталозі, відкрийте консоль Node.js і введіть такі рядки:
const dayjs = require('dayjs');
dayjs().format('YYYY MM-DDTHH:mm:ss')
Модуль dayjs
завантажується з ключовим словом require
. Коли викликається метод з модуля, бібліотека бере поточну системну дату і час і виводить їх у зазначеному форматі:
2020 11-22T11:04:36
Це той самий механізм, який використовувався у попередньому прикладі, коли середовище виконання Node.js завантажує в код функцію стороннього розробника.
Функціональність сервера
Оскільки Node.js контролює серверну частину вебзастосунків, одним із його основних завдань є обробка HTTP-запитів.
Ось короткий опис того, як вебсервери обробляли вхідні запити HTTP. Функція сервера полягає в тому, щоб прослуховувати запити, якомога швидше визначати, яка відповідь потрібна кожному з них, і повертати цю відповідь відправнику запиту. Ця програма повинна отримати вхідний запит HTTP, ініційований користувачем, проаналізувати запит, виконати обчислення, згенерувати відповідь і надіслати її назад. Використовується такий модуль HTTP, як Node.js, оскільки він спрощує ці кроки, даючи змогу вебпрограмісту зосередитися на самій програмі.
Розглянемо наступний приклад, який реалізує цю базову функціональність:
const http = require('http');
const url = require('url');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
const queryObject = url.parse(req.url,true).query;
let result = parseInt(queryObject.a) + parseInt(queryObject.b);
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(`Result: ${result}\n`);
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
Збережіть цей контент у файлі під назвою basic_server.js
і запустіть його за допомогою команди node
. Термінал, на якому запущено Node.js, відобразить таке повідомлення:
Server running at http://127.0.0.1:3000/
Потім перейдіть за такою URL-адресою у своєму браузері:`\http://127.0.0.1:3000/numbers?a=2&b=17`
Node.js запускає вебсервер на вашому комп’ютері та використовує два модулі: http
та url
. Модуль http
налаштовує базовий HTTP-сервер, обробляє вхідні вебзапити та передає їх нашому простому коду програми. Модуль URL аналізує аргументи, передані в URL-адресі, перетворює їх у цілочисельний формат і виконує операцію додавання. Потім модуль `http' надсилає відповідь у вигляді тексту до браузера.
У справжньому вебзастосунку Node.js зазвичай використовується для обробки та отримання даних, як правило, з бази даних, і повернення обробленої інформації інтерфейсу для відображення. Але базовий застосунок в цьому уроці лаконічно показує, як Node.js використовує модулі для обробки вебзапитів в якості вебсервера.
Вправи до посібника
-
Які причини використовувати модулі замість написання простих функцій?
-
Чому середовище Node.js стало таким популярним? Наведіть одну характеристику.
-
Яке призначення файлу
package.json
? -
Чому не рекомендується зберігати та ділитися папкою
node_modules
?
Дослідницькі вправи
-
Як ви можете виконувати застосунки Node.js на своєму комп’ютері?
-
Як ви можете розмежувати параметри в URL-адресі для подальшого аналізу сервером?
-
Опишіть сценарій, у якому конкретне завдання може бути вузьким місцем для програми Node.js.
-
Як би ви реалізували параметр для множення або підсумовування двох чисел у серверному прикладі?
Підсумки
Цей урок надає огляд середовища Node.js, його характеристики та можливості використання для реалізації простих застосунків. В уроці розглянуті такі поняття:
-
Що таке Node.js і чому він використовується.
-
Як запускати програми Node.js з командного рядка.
-
Цикли подій і єдиний потік.
-
Модулі.
-
Диспетчер пакунків Node (NPM).
-
Функціональність сервера.
Відповіді до дослідницьких вправ
-
Які причини використовувати модулі замість написання простих функцій?
Вибираючи модулі замість звичайних функцій, програміст створює базу коду більш простого для читання та підтримки та для написання автоматизованих тестів.
-
Чому середовище Node.js стало таким популярним? Наведіть одну характеристику.
Однією з причин є гнучкість мови JavaScript, яка вже широко використовувалася в інтерфейсі вебзастосунків. Node.js дає змогу використовувати одну мову програмування для всієї системи.
-
Яке призначення файлу
package.json
?Цей файл містить метадані проекту, такі як назва, версія, залежності (бібліотеки) тощо. Маючи файл
package.json
, інші люди можуть завантажувати та встановлювати одні й ті самі бібліотеки та запускати тести так само, як це робив оригінальний розробник. -
Чому не рекомендується зберігати та ділитися папкою
node_modules
?Папка
node_modules
містить реалізації бібліотек, доступних у віддалених репозиторіях. Отже, кращий спосіб поділитися цими бібліотеками — це вказати їх у файліpackage.json
, а потім використовувати NPM для завантаження цих бібліотек. Цей метод більш простий і безпомилковий, оскільки вам не потрібно відстежувати та підтримувати бібліотеки локально.
Відповіді до дослідницьких вправ
-
Як ви можете виконувати застосунки Node.js на своєму комп’ютері?
Ви можете запустити їх, увівши
node PATH/FILE_NAME.js
у командному рядку вашого терміналу, змінившиPATH
на шлях до вашого файлу Node.js і змінившиFILE_NAME.js
на вибране ім’я файлу. -
Як ви можете розмежувати параметри в URL-адресі для подальшого аналізу сервером?
Символ амперсанда
&
використовується для розмежування цих параметрів, щоб їх можна було витягти та проаналізувати в коді JavaScript. -
Опишіть сценарій, у якому конкретне завдання може бути вузьким місцем для програми Node.js.
Node.js не є хорошим середовищем для виконання процесів із інтенсивним використанням процесора, оскільки він використовує один потік. Сценарій чисельних обчислень може уповільнити та заблокувати всю програму. Якщо потрібне чисельне моделювання, краще використовувати інші інструменти.
-
Як би ви реалізували параметр для множення або підсумовування двох чисел у серверному прикладі?
Використовуйте потрійний оператор або умову if-else, щоб перевірити наявність додаткового параметра. Якщо параметром є рядок
mult
, повертайте добуток чисел, інакше повертайте суму. Замініть старий код фрагментом нижче. Перезапустіть сервер у командному рядку, натиснувши kbd:[Ctrl+C] і повторно запустивши команду, щоб перезапустити сервер. Тепер перевірте новий застосунок, відвідавши URL-адресуhttp://127.0.0.1:3000/numbers?a=2&b=17&operation=mult
у своєму браузері. Якщо ви опустите або зміните останній параметр, результатом буде сума чисел.let result = queryObject.operation == 'mult' ? parseInt(queryObject.a) * parseInt(queryObject.b) : parseInt(queryObject.a) + parseInt(queryObject.b);