009 Сравнение сред выполнения JS
NodeJS имеет своё собственное API, которое несовместимо с браузером, поэтому могут быть некоторые сложности из-за несовместимости со стандартным JS (в браузере). Так же нода имеет свои глобальные переменные, так как она работает непосредственно с ПК
Так же есть и более свежый вариант бэка на JS - это Deno. Единственная его проблема заключается в том, что он пока очень молод и коммьюнити не такое и большое.
010 Запускаем код и REPL
REPL-режим - это режим, при котором мы можем запустить определённую среду в консоли
Запускается REPL в ноде командой:
И работать в этом режиме так же как и в браузере
Создаём поток чтения fs
, который будет читать наш текстовый файл и выводить его в консоль
011 Модули в JavaScript
Плюсы модулей:
История выраженности нужности импортов достаточно небольшая и она состояла из трёх этапов:
- IIFE функции
- Второй стандарт появился в NodeJS и работал через
require
. Для работы в браузере он требовал сборку в один файл (через сборщики модулей) - Последняя версия стандарта появилась сначала для работы на фронте, но в последние несколько лет её можно использовать и на бэке
Самые первые импорты - IIFE. Это функции, которые вызвались самостоятельно. Внутри них происходил не просто самовызов на странице пользователя, а взаимное связывание и присвоение отдельных компонентов функции к главному скриптовому файлу. Порядок подключения был важен.
Второй способ - CommonJS . В первую очередь, они работают именно на бэке. Для работы на фронте им был нужен сборщик модулей, который собирал бы на ноде файл в один модуль.
И последний способ импорта - ES Modules. Особенность ноды заключается в том, чтобы использовать современные импорты, нужно использовать расширение .mjs
Главным преймуществом CommonJS является то, что его можно использовать в любом месте кода, а так же в условиях (что позволяет нам не подключать какой-либо модуль, если нам то не нужно) Главным преймуществом ES Modules является то, что он подключает только указанные части модуля, а не его полностью (если то не требуется) + он асинхронен (не останавливает выполнение приложения, если импорт не подгрузился)
Подключить модули в NodeJS можно тремя способами:
012 CommonJS Modules
Напишем небольшой пример, где мы будем определять владельца кольца.
С помощью module.exports = { имена экспортов };
мы определяем, что будем экспортировать из модуля
characters.js
Уже тут через деструктуризацию и функцию require()
, мы получаем доступ к экспортированным объектам модуля
app.js
И дальше нужно переписать код так, чтобы функция работала правильно и не мутировала внутри себя значение, а возвращала изменённое значение вовне.
так же экспортировать можно непосредственно и функцию прямо на месте её создания
Круговые зависимости, когда у нас есть импорты и экспорты между двумя файлами - могут привести к ошибке (потому как интерпретатор будет пытаться достучаться до элемента, которого пока не существует)
И тут далее можно увидеть пример, когда мы подгружаем модуль в проект по условию (при выполнении условия - модуль подгружается)
013 ES Modules
Чтобы сказать ноде, что мы пользуемся модулями, нужно:
- Либо добавить расширение файлу
.mjs
- Либо указать это в
package.json
- Либо в
tsconfig
В обычной модульной системе, мы можем через export
экспортировать объект из модуля
characters.mjs
Далее через конструкцию import
импортировать его в другом файле
app.mjs
Так же мы можем импортировать сразу все объекты через конструкцию * as имя
app.mjs
Так же мы имеем дефолтный экспорт export default
- это принимаемое значение из модуля по умолчанию
characters.mjs
app.mjs
Так же нам ничто не мешает объединять конструкции и импортировать дефолтную функцию + все объекты модуля
app.mjs
Дальше мы можем столкнуться с такой проблемой при большом количестве импортов, что имена совпадают у объектов. Чтобы решить проблему, можно переопределить импортируемый объект
app.mjs
Так же присутствует в ноде асинхронный импорт модуля, который позволяет произвести es module испорт из любого места. Сразу нужно сказать, что он возвращает промис, поэтому его нужно дожидаться
app.mjs
Так же никто нам не мешает ловить и обрабатывать ошибки при данных импортах
app.mjs
По возможности стоит пользоваться конкретно таким импортом, потому что он позволяет импортировать только то, что нужно, он асинхронен и удобен
014 Глобальные переменные
Глобальные переменные - это переменные, доступ к которым мы можем получить из любого места приложения без дополнительных импортов и вызовов.
Модули делятся на глобальные и глобальные модульные. Конкретно вторые зависят от того модуля, из которого мы их вызваем
Модуль global
- это корневой объект всех переменных. Мы можем записать global.console
, а так же и просто console
- Группа глобальных объектов, которые не категоризируются
preformance
- помогает определить производительностьBuffer
- читает набор байтAbortController
- позволяет прерывать API, основанные на промисахqueueMicrotask
- это планировщик задач дляV8
WebAssembly
- хранит модулиWebAssembly
- Группа таймеров
- Группа работы с URL
- Группа работы с сообщениями (используются в вебсокетах)
- Группа работы с событиями
- Группа работы с текстом (например, перевод текста в другую кодировки и обратно)
- Группа модулей
__dirname
- получает путь до модуля__filename
- получает имя файлаexports
module
require()
__dirname
возвращает нам просто путь до нашего модуля
А уже __filename
возвращает нам путь с именем файла
015 Events
Модуль Event Emitter - это модуль, который позволяет обмениваться сообщениями между модулями внутри приложения на ноде. Мы как и на фронте можем подписаться на определённый ивент и при срабатывании ивента передавать определённое сообщение в другой модуль
Есть два способа генерировать события для наших модулей системы, но стоит пользоваться только одним - Event Emitter, который полностью покрывает все потребности в повседневной разработке
Через функции addListener
и on
мы подписываем слушателя на определённые события и можем выполнять их через emit
.
Чтобы удалить события, нам нужно воспользоваться removeListener
, removeAllListeners
или off
. Удалять события важно, так как они отвечают за огромные утечки памяти.
app.js
Таким образом мы можем передавать данные в наши листенеры
app.js
Так же функция once()
позволяет создать событие, которое сработает только однажды, а потом удалится
app.js
Мы можем определить своё собственное максимальное количество слушателей на наше событие и получить это количество
app.js
Так же у листенеров есть порядок выполнения. Самыми первыми выполняются те, что находятся в начале массива. Мы можем влиять на выполнение этих листенеров определёнными методами.
Тут мы можем вывести все имена наших имеющихся событий
Так же ивенты можно использовать для обработки ошибок в приложении
Использование Event Target (не рекомендуется):