Node JS фундаментальный курс от А до Я. Node.js Теория и практика

YOUTUBE · 18.11.2025 18:28

Ключевые темы и таймкоды

Введение и план курса

0:03
  • Третий фундаментальный курс по Node.js.
  • План: установка Node.js, npm, концепции Node.js, движок V8, синхронная модель, блокирующий и неблокирующий ввод-вывод, многопоточность, шаблон реактора, де-мультиплексор событий, событийно-ориентированная модель Node.js, особенности Event Loop Node.js.

Практическая часть

0:41
  • Работа со стандартными модулями Node.js: процесс, fs, os, cluster.
  • Создание событий и работа со стримами.
  • Клиент-серверная составляющая: модуль http, создание фреймворка по типу Express.

Дальнейшее обучение

1:26
  • План на дальнейшее обучение: работа с фреймворками Express, Nest, работа с базами данных PostgreSQL, MongoDB, авторизация с использованием Refresh Token.
  • Домашнее задание на Patreon.

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

2:04
  • Установка Node.js с официального сайта.
  • Проверка версии Node.js и npm в терминале.

Работа с WebStorm

2:33
  • Создание первого файла с исходным кодом в WebStorm.
  • Запуск файла в терминале с помощью команды `node`.

npm

3:10
  • npm как менеджер пакетов Node.js.
  • Установка и удаление пакетов с помощью npm.

Инициализация проекта

4:00
  • Инициализация проекта с помощью команды `npm init`.
  • Создание файла package.json.

Установка зависимостей

5:00
  • Установка зависимостей для разработки и продакшна.
  • Рекурсивная установка зависимостей в папку `node_modules`.

Теория Node.js

6:07
  • Node.js как программная платформа, преобразующая JavaScript в машинный код.
  • Преимущества Node.js: простота освоения, высокая скорость работы, единство фронт- и бэкенд-разработки, богатый менеджер пакетов npm, быстрое прототипирование.

Преимущества Node.js

8:08
  • Простота освоения для тех, кто знает JavaScript.
  • Высокая скорость обработки запросов благодаря неблокирующему вводу-выводу.
  • Единство фронт- и бэкенд-разработки на одном языке.
  • Богатый менеджер пакетов npm с миллионами пакетов.
  • Быстрое прототипирование продуктов.

Концепции Node.js

9:12
  • Node.js преобразует исходный код JavaScript в машинный код с помощью движка V8.
  • V8 разработан Google и используется в браузере Chrome.
  • V8 компилирует и выполняет исходный код, выделяет память для объектов и собирает мусор.

Кроссплатформенные операции ввода-вывода

10:11
  • Libuv обеспечивает кроссплатформенные операции ввода-вывода, такие как работа с файловой системой и сетью.
  • Libuv предоставляет программный интерфейс для взаимодействия с различными операционными системами.

Цикл событий

11:06
  • Цикл событий позволяет разрабатывать асинхронные приложения без необходимости создания физических потоков.
  • Node.js продолжает выполнять другие операции до получения результатов операций ввода-вывода.

Преимущества и недостатки цикла событий

13:22
  • Преимущества: высокая скорость обработки простых операций ввода-вывода.
  • Недостатки: сложность управления асинхронным кодом и высокая нагрузка на сложные вычисления.

Блокирующий ввод-вывод

14:25
  • Блокирующий ввод-вывод использует потоки для обработки операций, но потребляет много ресурсов и сложен в управлении.
  • Потоки могут простаивать, потребляя ресурсы, и вызывать взаимные блокировки.

Неблокирующий ввод-вывод

17:30
  • Неблокирующий ввод-вывод позволяет системным вызовам немедленно возвращать управление, не ожидая выполнения операций.
  • Основной шаблон реализации — активный опрос ресурсов в цикле ожидания.
  • Более эффективный механизм — демульиплексор событий.

Сравнение веб-серверов

18:37
  • Apache использует блокирующую модель, создавая новый поток для каждого соединения.
  • Nginx работает по неблокирующему принципу, обрабатывая запросы быстрее.
  • При росте одновременных подключений Nginx обрабатывает запросы примерно в 2,5 раза быстрее, чем Apache.

Введение в Node.js и неблокирующий ввод-вывод

19:07
  • Node.js использует неблокирующую модель ввода-вывода.
  • JavaScript однопоточный, синхронность достигается через event-loop.
  • Node.js однопоточный, но использует потоки под капотом.

Основы работы Node.js

20:04
  • В основе Node.js лежит libuv, который управляет потоками.
  • По умолчанию используется четыре потока, количество можно изменять.
  • Неблокирующий ввод-вывод требует распараллеливания тяжёлых операций.

Пример использования криптографической функции

21:04
  • Импортируется модуль crypto для криптографических операций.
  • Вызывается функция шифрования с параметрами пароль, соль, количество итераций.
  • Функция является асинхронной и неблокирующей.

Анализ времени выполнения функции

22:01
  • Измеряется время выполнения функции хэширования.
  • Несколько вызовов функции выполняются параллельно.
  • Пятый вызов выполняется позже из-за планирования потоков.

Роль планировщика потоков

23:57
  • Планировщик потоков выделяет ресурсы для выполнения задач.
  • Пул потоков содержит четыре потока по умолчанию.
  • Пятый вызов функции выполняется позже из-за освобождения потоков.

Модуль worker_threads

24:53
  • С версии 11.7 в Node.js добавлен модуль worker_threads для управления потоками.

Демультиплексор событий и шаблон реактор

25:31
  • Демультиплексор событий обеспечивает неблокирующий ввод-вывод.
  • Шаблон реактор включает event-loop, очередь событий и обработчики.
  • Приложение обрабатывает запросы ввода-вывода и события.

Последовательность взаимодействия компонентов

27:31
  • Приложение создаёт операцию ввода-вывода и определяет обработчик.
  • Демультиплексор добавляет новые события в очередь.
  • Цикл событий обрабатывает события и вызывает обработчики.

Совместимость с разными ОС

29:39
  • Каждая ОС имеет свой интерфейс для демультиплексора событий.
  • В Unix обычные файлы не поддерживают неблокирующие операции.
  • Библиотека libuv обеспечивает совместимость Node.js со всеми основными платформами.

Функции библиотеки libuv

30:26
  • Libuv реализует шаблон реактор и обеспечивает программный интерфейс для циклов событий.
  • Управление очередью событий, выполнение асинхронных операций ввода-вывода и организация очереди задач разных типов

Event Loop в Node.js

30:45
  • Node.js инициализирует цикл событий Event Loop при запуске.
  • Цикл обрабатывает код, выполняющий асинхронные операции и настраивающий таймеры.
  • Диаграмма на слайде показывает порядок выполнения операций в цикле событий.

Фазы цикла событий

31:45
  • Первая фаза: таймеры, выполняются колбеки, запланированные функциями setTimeout и setInterval.
  • Вторая фаза: колбеки ввода и вывода, выполняются почти все колбеки, кроме событий close-таймеров и событий, определённых с помощью setImmediate.
  • Третья фаза: ожидания и подготовка, используется только для внутренних целей.
  • Четвёртая фаза: опрос, получение новых событий ввода и вывода, Node.js может блокироваться на этом этапе.
  • Пятая фаза: проверка, вызываются колбеки, определённые с помощью setImmediate.
  • Шестая фаза: события close, например, закрытие веб-сокет соединения.

Практика с Node.js

33:02
  • Знакомство с глобальным объектом process, который позволяет получить информацию о текущем процессе, включая уникальный идентификатор.
  • Демонстрация работы с диспетчером задач и остановкой процесса.

Переменные окружения

34:33
  • Переменные окружения доступны через поле env объекта process.
  • Инициализация переменных через скрипты и пакет cross-env.
  • Использование файла .env для настройки переменных.

Аргументы и завершение процесса

37:49
  • Передача аргументов при запуске приложения.
  • Завершение процесса по условию с помощью метода exit.

Взаимодействие с файловой системой

38:47
  • Модуль path для работы с абсолютными и относительными путями.
  • Метод join для склеивания участков пути, учитывающий различия в разделителях на разных ОС.
  • Глобальные переменные dirname и filename для получения пути к текущей директории и файлу.

Гибкость путей

40:09
  • Использование точек для возврата на один уровень вложенности в папках.
  • Гибкое перемещение между папками для получения нужных путей.

Функция resolve

40:59
  • Функция resolve возвращает абсолютный путь, в отличие от join.
  • Добавление слэшей в аргументы меняет тип пути.
  • Без слэшей возвращается абсолютный путь от корня до последнего аргумента.

Парсинг путей

41:55
  • Функция parse позволяет распарсить путь и получить корень, директорию, название файла и его расширение.
  • Дополнительные методы и свойства доступны для работы с путями.

Работа с URL

42:53
  • Класс URL используется для разбора строк с URL.
  • Объект URL содержит протокол, хост, порт, параметры и путь.

Взаимодействие с файловой системой

44:12
  • Модуль fs используется для создания, удаления, чтения и записи файлов.
  • Методы fs бывают синхронными и асинхронными.

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

44:32
  • Функция mkdir создаёт папку, требуя путь к директории.
  • Для рекурсивного создания папок нужно передать объект с свойством recursive=true.

Асинхронные функции

45:52
  • Асинхронные функции работают через колбеки, которые обрабатывают ошибки.
  • Пример обработки ошибок и вывода сообщений в консоль.

Удаление папок

47:32
  • Функция remove удаляет папку, требуя путь и колбек.
  • Обработка ошибок в колбеке.

Создание и запись в файл

48:05
  • Функция writeFile создаёт файл и записывает данные, перезаписывая существующие.
  • Функция appendFile добавляет данные в конец файла.

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

50:01
  • Promises позволяют улучшить читаемость кода, избегая «ад колбеков».
  • Возможность работы с файловой системой через promises в новых версиях Node.js.

Реализация функции записи файла с использованием промисов

50:36
  • Создаём функцию, возвращающую промис.
  • Промис принимает колбек, который обрабатывает успех или ошибку.
  • Используем функцию `writeFile` из стандартного модуля Node.js, указывая путь и обрабатывая ошибки.

Дублирование функции и передача данных

51:33
  • Дублируем функцию для записи файла.
  • Передаём путь и данные в функцию `writeFile` через аргументы.
  • Избегаем жёсткого кодирования данных для универсальности функций.

Преимущества использования промисов

52:29
  • Промисы делают код более читабельным и удобным для обработки ошибок.
  • Пример показывает, как ошибки обрабатываются в одном месте, а не разбрасываются по коду.

Методы работы с файлами

53:28
  • Обсуждаются методы для изменения доступа, чтения, открытия, копирования и перемещения файлов.

Реализация функции чтения файла

53:52
  • Создаём функцию `readFile` для чтения данных из файла.
  • Указываем кодировку UTF-8 для получения строки.
  • Обрабатываем данные в колбеке, получая строку или буфер.

Удаление файла

55:41
  • Реализуем функцию удаления файла с помощью `rm`.
  • Проверяем удаление файла, выводя информацию в логи.

Задача с переменными окружения

56:27
  • Получаем строку из переменной окружения, записываем её в файл, считываем, считаем количество слов и записываем результат в другой файл.
  • Удаляем первый файл после выполнения задачи.

Взаимодействие с операционной системой

58:59
  • Импортируем модуль `os` для получения информации об операционной системе и процессоре.
  • Используем функции `platform` и `cpu` для получения информации о текущей ОС и архитектуре процессора.

Модуль `cluster` для многопоточности

1:00:51
  • Модуль `cluster` позволяет однопоточному приложению использовать многоядерные системы.
  • Проверяем, является ли текущий процесс главным, и запускаем дочерние процессы с помощью `fork`.
  • Выводим ID процесса в логи и проверяем его работу каждые 5 секунд.

Запуск и управление воркерами

1:02:21
  • Запуск приложения и создание нескольких воркеров.
  • Управление процессами через диспетчер задач и терминал.
  • Обработка ошибок и событий exit с помощью EventEmitter.

Обработка событий exit

1:02:47
  • Подписание на события exit для обработки ошибок.
  • Запуск новых процессов при смерти существующих.
  • Использование кодов сигналов для управления процессами.

Масштабирование Node.js приложений

1:04:25
  • Различные подходы к масштабированию: балансировщики, кластеризация, Docker-контейнеры.
  • Упоминание о возможности записи ролика по масштабированию Node.js приложений.

Модуль EventEmitter

1:05:06
  • Импорт модуля EventEmitter и создание объекта Emitter.
  • Создание пользовательских событий с помощью функции on.
  • Генерация событий с помощью функции emit.

Применение событийно-ориентированной модели

1:07:04
  • Использование событий в Node.js для обмена сообщениями и кластеризации.
  • Пример генерации события при смерти процесса.

Функции для работы с событиями

1:07:58
  • Функция once для генерации событий единожды.
  • Функции removeAllListeners и removeListener для управления слушателями.

Введение в стримы

1:09:05
  • Объяснение различий между тредами и стримами.
  • Типы стримов: readOnly, writeOnly, duplex, transform.
  • Пример использования стримов для чтения и записи файлов по кусочкам.

Практическое использование стримов

1:11:00
  • Импорт модулей fs и path.
  • Чтение файла с помощью функции readFile и стримов.
  • Подписание на события дата и обработка изменений.

Обработка ошибок и опции стримов

1:13:50
  • Важность обработки ошибок при работе со стримами.
  • Опции стримов: кодировка, автозакрытие, получение текста без буферов.
  • Переход к рассмотрению writeOnly стримов.

Запись в файл

1:14:37
  • Указываем путь к файлу «тест2.txt».
  • Создаём цикл для записи данных в файл, выполняя 20 итераций.
  • Используем метод `write` для записи данных в файл.
  • Завершаем запись с помощью функции `end`.

Методы закрытия стрима

1:15:34
  • Методы `close` и `destroy` вызывают разные события.
  • Подписываемся на события для обработки закрытия стрима.

Работа со стримами в HTTP-сервере

1:15:55
  • Объекты `request` и `response` являются стримами.
  • `request` — это `read_bytes_stream`, а `response` — `write_bytes_stream`.
  • Синхронизация чтения и записи данных с помощью метода `pipe`.

Создание HTTP-сервера

1:17:35
  • Импортируем модуль `aтипи` и создаём сервер с помощью метода `create_server`.
  • Обрабатываем входящие соединения с помощью `request_listener`.
  • Запускаем сервер на определённом порту, получая его из переменных окружения.

Запуск сервера и работа с заголовками

1:18:45
  • Запускаем сервер и проверяем его работу.
  • Указываем заголовки для корректной работы с кириллицей: `status_code`, `content_type`, `charset`.
  • Применяем сервер-сайт-рендеринг для отправки разметки на клиент.

REST API и JSON

1:20:26
  • Используем поле `url` для генерации эндпойнтов.
  • Возвращаем данные в формате JSON, добавляя заголовок `content_type`.
  • Преобразуем JavaScript-объекты в строки для отправки.

Реализация маршрутизатора

1:22:04
  • Создаём класс `Router` с конструктором и объектом `end_points`.
  • Реализуем метод `register` для добавления эндпойнтов.
  • Генерируем события с помощью `event_emitter` для обработки запросов.

Абстракция маршрутизации

1:25:59
  • Создаём методы-оболочки для `register`: `get`, `post`, `put`, `delete`.
  • Эти методы упрощают работу с маршрутизацией, как в Express.

Работа с методами и событиями

1:26:23
  • Создание GET-запроса по адресу /users с передачей пути и колбека.
  • Генерация событий при создании сервера с использованием функции emit.
  • Передача параметров рек и респонс при эмитировании событий.

Обработка несуществующих маршрутов

1:27:23
  • Обработка бесконечной загрузки при запросе несуществующего маршрута.
  • Закрытие стрима при отсутствии события для предотвращения бесконечной загрузки.

Организация фреймворка

1:28:25
  • Вынесение кода в отдельный пакет для повторного использования.
  • Экспорт класса Router с помощью модуля export.
  • Импорт роутера в индексный файл.

Создание класса Application

1:29:40
  • Создание класса Application с инкапсуляцией EventEmitter и HTTP-сервера.
  • Инициализация сервера через приватный метод.

Получение маски маршрута

1:30:59
  • Вынесение получения маски маршрута в отдельный метод.
  • Использование маски при инициализации и эмитировании событий.

Добавление роутеров

1:31:55
  • Итерация по эндпойнтам роутера и подписка на соответствующие события.
  • Перенос кода подписки на события в класс Application.

Запуск сервера

1:33:24
  • Реализация функции run в классе Application для запуска сервера.
  • Передача порта и колбека при запуске сервера.

Декомпозиция маршрутов

1:34:05
  • Создание папки src и файла для описания маршрутов пользователей.
  • Импорт роутера и добавление эндпойнта для обработки GET-запросов.

Преобразование данных и добавление заголовков

1:35:05
  • Преобразование массива пользователей в JSON-строку с помощью функции stringify.
  • Добавление заголовка Content-Type для корректного восприятия данных браузером.

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

1:36:59
  • Отправка запросов с помощью Postman для тестирования маршрутов.
  • Демонстрация необходимости указания Content-Type для корректного ответа.

Создание Middleware

1:38:03
  • Экспорт функции Middleware для парсинга JSON и проставления заголовков.
  • Реализация метода send для отправки данных в формате JSON.

Реализация функционала для добавления мидл-версий

1:38:28
  • Создаём метод `use`, который принимает мидл-версию в качестве аргумента.
  • В конструкторе инициализируем массив мидл-версий для вызова перед каждым запросом.
  • Перед вызовом хендлера обрабатываем запрос, итерируясь по массиву мидл-версий с помощью `forEach`.

Подключение мидл-версии для парсинга JSON

1:39:22
  • Импортируем мидл-версию для парсинга JSON из папки `framework`.
  • Вызываем функцию `use` с ссылкой на JSON-парсер.
  • Теперь в эндпойнтах не нужно вручную прописывать заголовки и парсить JSON, всё происходит автоматически.

Исправление ошибки при отправке GET-запроса

1:40:03
  • Получаем ошибку типа из-за неправильного импорта JSON-парсера.
  • Исправляем импорт и отправляем запрос снова.
  • Подтверждаем, что получаем JSON-массив с объектами без необходимости ручного парсинга.

Работа с POST-запросом и телом запроса

1:40:35
  • Выводим тело запроса в логи и добавляем объект в массив.
  • Отправляем POST-запрос с телом в формате JSON, но получаем пустой ответ.
  • Читаем тело запроса с помощью стрима, подписываясь на события `data` и `end`.

Преобразование тела запроса в JavaScript-объект

1:42:13
  • Преобразуем тело запроса из строки в JavaScript-объект с помощью функции `parse`.
  • Эмитируем событие `parsing` после завершения чтения тела запроса.

Работа с URL-параметрами

1:43:12
  • Создаём мидл-версию для парсинга URL-параметров.
  • Используем модуль `URL` для анализа URL.
  • Получаем полный маршрут с протоколом, портом и хостом.

Преобразование URL-параметров и настройка маршрутизации

1:45:06
  • Создаём функцию, которая возвращает мидл-версию с базовым URL.
  • Передаём базовый URL в конструктор `URL`.
  • Изменяем вызов мидл-версий перед генерацией событий для доступа к `pathname`.

Обработка URL-параметров в роутере

1:46:55
  • Добавляем `pathname` в объект запроса для правильной маршрутизации.
  • Инициализируем объект для работы с URL-параметрами.
  • Итерируемся по полю `searchParams` и добавляем параметры в объект.

Проверка работы запроса в Postman

1:48:34
  • Отправка запроса в Postman показывает объект с параметрами ID и номер страницы.
  • Проверка ID в параметрах позволяет найти конкретного пользователя в массиве.
  • Проблема с строгим сравнением чисел и строк решается путём преобразования параметров в строки.

Декомпозиция функций

1:49:31
  • Функции-обработчики в роутере становятся неудобными для управления.
  • Создание файла user-controller с функциями getUser и createUser.
  • Экспорт функций в объект и импорт в роутер.

Тестирование функционала

1:50:30
  • Проверка работы функций через Postman: получение пользователя по ID и массива без ID.
  • Добавление нового элемента в массив через POST-запрос.

Работа с MongoDB и Mongoose

1:51:20
  • Установка Mongoose для удобного взаимодействия с MongoDB.
  • Регистрация на сайте MongoDB и создание проекта.
  • Выбор бесплатного кластера и сервера.

Создание схемы и модели

1:52:36
  • Импорт Mongoose в index.js и создание функции start для подключения к базе данных.
  • Описание схемы пользователя в файле user-schema.
  • Экспорт модели пользователя с помощью функции model.

Реализация функций с Mongoose

1:54:23
  • Создание константы users и вызов функции find для получения всех записей из базы данных.
  • Проверка параметров ID и получение конкретного пользователя по ID.
  • Использование функции create для создания пользователя.

Подключение к базе данных

1:55:22
  • Создание пользователя для подключения к базе данных и разрешение доступа с IP-адреса.
  • Копирование URL базы данных и указание пароля.
  • Запуск сервера и проверка работы через Postman.

Проверка коллекции в MongoDB

1:57:01
  • Просмотр коллекции пользователей в MongoDB.
  • Подтверждение наличия трёх документов в коллекции.

Рекомендации по дальнейшему обучению

1:57:28
  • Рекомендация ознакомиться с фреймворком Express.js и MongoDB.
  • Изучение революционных баз данных и работы с SQL.
  • Основы авторизации и работа с ролями пользователей.
  • Продвинутые темы: Nest.js, GraphQL, веб-сокеты.
  • Практические проекты: Telegram-бот, музыкальная платформа, интернет-магазин, облачное хранилище.
  • Разговорные ролики: собеседование с junior-разработчиком, знания для junior-разработчика.