NodeJS: быстрый старт



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

    Преподаватель — Александр Коржиков, Dev IT Engineer в компании ING Group (Нидерланды).






    Несколько слов о Node.js


    Node.js — это асинхронная среда исполнения JavaScript, в основе которой находятся такие понятия, как Event Loop и событийно-ориентированная архитектура. Платформа Node.js и стандартный пакетный менеджер NPM позволяют создавать эффективные приложения для различных предметных областей — от Web и до Machine Learning.

    Самый простой пример web-сервера (node server.js):

    const http = require('http')
    const hostname = '127.0.0.1'
    const port = 3000
    const server = http.createServer((req, res) => {
    res.statusCode = 200
    res.setHeader('Content-Type', 'text/plain')
    res.end('Hello World\n')
    })
    server.listen(port, hostname, () => {
    console.log(`Server running at http://${hostname}:${port}/`)
    })
    

    Глядя на код выше, можно отметить следующие особенности Node.js:

    1. Мы можем запустить JavaScript-код прямо на сервере, то есть возможно исполнение JavaScript-файлов с помощью команды node.
    2. Поддерживается CommonJS-формат модулей для загрузки зависимостей и ES Modules, причём можно использовать оба формата.
    3. Поддерживается стандартная библиотека модулей, частью которой является HTTP.
    4. API основано на асинхронном паттерне Callbacks, но также поддерживаются Promise.
    5. Поддерживается синтаксис ES2015. Кстати, вот полезная ссылка, с помощью которой всегда можно посмотреть, в какой версии Node какие функции JS поддерживаются. Если что-то идёт не так, можно сравнить и понять, в чём проблема.

    Также не пропустите небольшое демо (VSCode + Chrome Debug).

    Краткий экскурс в историю


    Платформа Node.js появилась в 2009 году, основным разработчиком и создателем проекта был Ryan Dahl. Его главная идея заключалась в создании неблокирующего I/O (input-output) для сервера, причём с использованием JavaScript. В то время такие подходы были не очень распространены, и JavaScript был одним из наилучших решений.

    Node.js использует внутри себя движок Chromium, точнее, ту его часть, которая интерпретирует JavaScript — V8. Именно благодаря тому, что интерпретатор в своё время отделился в отдельный проект V8, стало возможным просто создать экосистему вокруг него. Собственно говоря, именно это и сделал создатель Node.js Ryan Dahl. Кстати, сегодня существует Node.js Foundation — организация, которая занимается поддержкой проекта.



    Структура


    Во-первых, библиотека написана на C++ и JavaScript. Сам проект лежит на GitHub, поэтому, если любопытно, можете ознакомиться с его исходным кодом. Углубляться в его изучение можно очень долго)).

    Во-вторых, как уже было сказано, в неё входит V8 (платформа исполнения JavaScript от Google) и libuv как часть Event Loop (асинхронный событийный цикл).

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

    Также стоит сказать про основные паттерны проектирования, которые обычно используются в Node.js:

    • Callback (его уже упоминали);
    • Observer (более простой событийный паттерн);
    • Module (хотя он сейчас организован и в самом языке JavaScript, в Node.js он до сих пор актуален);
    • Reactor (паттерн асинхронного взаимодействия с какими-то ресурсами, когда вы не блокируете основной поток кода). Этот паттерн хорошо знаком JS-разработчикам. К примеру, если мы работаем в браузере и пишем фронтенд, мы не блокируем всю работу браузера, а просто подписываемся на события от пользователя, и, когда событие наступает (после «клика», «enter» и т. д.), мы выполняем наш код.

    Кстати, вот вам небольшое соревнование, которое провели на вебинаре)). И двигаемся дальше.

    Модули стандартного дистрибутива Node




    Знаете ли вы, какие модули включены в стандартный дистрибутив Node? То есть речь идёт о модулях, которые уже встроены, следовательно, их можно не устанавливать. Вообще, их около 50, давайте перечислим основные. Для удобства восприятия условно разделим их на 5 пунктов:

    1. Main (для обычных операций):

    • fs;
    • timers;
    • streams (для работы с потоками).

    2. Utilities:

    • path (для работы с путями);
    • util;
    • zlib (архивация и разархивация);
    • crypto (для криптографических функций).

    3. Processes (всё, что касается многопроцессности и параллельности):

    • child_process (основной модуль запуска второстепенных модулей, предоставляет большие возможности именно по запуску и слежению процессов);
    • cluster (похож на первый, но позволяет распараллеливать задачи на ядрах вашего процессора);
    • worker_threads (реализация нитей или потоков, но она не совсем поточная, а почему, лучше читать в документации).

    4. Protocols (всевозможные протоколы):

    • http(s);
    • net;
    • dns.

    5. System (соответственно, системные модули, включая отладочные):

    • os;
    • v8;
    • async_hooks;
    • perf_hooks;
    • trace_events.

    Что ещё добавить:

    — globals объект — аналог window;
    — все объекты JavaScript, которые доступны в браузере, также доступны и в Node.js;
    — timeouts — почти как в браузере;
    — process — репрезентация текущего процесса;
    — доступна console.

    Callbacks


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

    const server = http.createServer((req, res) => {
    res.statusCode = 200
    res.setHeader('Content-Type', 'text/plain')
    res.end('Hello World\n')
    })
    server.listen(port, hostname, () => {
    console.log(`Server running at http://${hostname}:${port}/`)
    })

    В Node по умолчанию callback выполняется с «ошибкой» и результатом асинхронно:

    fs.readFile('/etc/passwd', (err, data) => {
    if (err) throw err
    console.log(data)
    })
    

    А вот как выглядит антипаттерн — наглядный пример того, как неправильно использовать Callbacks. Как говорится, классический Callback Hell:

    fs.readdir(source, function (err, files) {
    if (err) {
    console.log('Error finding files: ' + err)
    } else {
    files.forEach(function (filename, fileIndex) {
    console.log(filename)
    gm(source + filename).size(function (err, values) {
    if (err) {
    console.log('Error identifying file size: ' + err)
    } else {
    console.log(filename + ' : ' + values)
    aspect = (values.width / values.height)
    widths.forEach(function (width, widthIndex) {
    height = Math.round(width / aspect)
    console.log('resizing ' + filename + 'to ' + height + 'x' + height)
    this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
    if (err) console.log('Error writing file: ' + err)
    })
    }.bind(this))
    }
    })
    })
    }
    })

    Теперь давайте посмотрим, как создать простой веб-сервер и отдать индекс HTML в виде ответа клиента:

    const http = require('http')
    const server = http.createServer((req, res) => {
    res.statusCode = 200
    res.setHeader('Content-Type', 'text/plain')
    res.end('Hello World\n')
    })
    

    Чтобы прочитать локальный html-файл:

    const fs = require('fs')
    fs.readFile('./index.html', (err, text) => {
    console.log(text)
    })

    Заканчивая тему колбэков, хотелось бы упомянуть про Callback Types. Бывают колбэки, которые возвращают только ошибку, если есть ошибка:

    fs.access('/etc/passwd', fs.constants.R_OK, (err) => {
    console.log(err ? 'no access!' : 'read')
    })
    

    Также сейчас всё больше и больше модулей и API используют Promises из коробки, и это хорошо. Node поддерживает Promises:

    util.promisify()
    fs.promises.*
    

    Тип возвращаемого значения:

    http.request('https://example.com', (error, response, body) => {
    ...
    })

    Node Q&A


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

    import express from "express";
    const app = express();
    const port = 3000;
    app.get("/", (req, res) => {
    res.send("Hello World!");
    });
    app.listen(port, () => {
    console.log(`Example app listening
    });



    Что же, теперь можете самостоятельно попробовать создать веб-сервер с Express-генератором:

    • с использованием jade, cookie-session;
    • сделав наивный login logout.

    Или сразу посмотрите, как это сделал преподаватель, подготовивший уже готовое решение на TypeScript.

    На этом всё. Напоследок — парочка полезных ссылок:


    И до встречи на курсе.
    OTUS. Онлайн-образование
    Цифровые навыки от ведущих экспертов

    Комментарии 1

      0
      было бы побольше инфы как на проде поддерживать node.js сервер )

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

      Самое читаемое