General Flashcards
Node.js vs Browser difference
Browser:
Interactive Web Applications
DOM, Window…
Need to support older versions of browsers
ES modules
Node:
Server applications
File system APIs, networking, cryptography…
Single version of Node on the server
CommonJS + ES modules
REPL
Read Eval Print Loop
Debugging mode
To enter it, write “node”.
Зачем нужны модули?
Изоляция
Организация файловой системы
Переиспользование
История модулей
1) IIFE
(const a = 2; APP.number = a)()
Работает только в браузере
2) require
module.exports = {a, b}
const {a,b} = require(some.js)
Работает только в Node, а в бразуере используется только для сборки. Webpack на самом деле собирает тоже всё на Node
3) ES модули
export
import
Отличия CommonJS от ES модулей
CommonJS Модули:
1) Require в пишем любом месте
2) Можно использовать в условиях
3) Загружает весь модуль, даже если импортируем небольшую часть
4) Синхронная загрузка модуля, может заблокировать поток
ES Модули:
1) Импорты всегда должны быть на верхнем уровне
2) Нельзя использовать в условиях (кроме асинхронных)
3) Выборочно загружает части их модуля
4) Асинхронная загрузка модуля
Как использовать ES модули в Node?
1) Работать с .mjs файлами
2) В package.json писать type: “module”
3) Передать node аргумент –input-type=module
Глобальные переменные
global - рутовый объект
console
performance
Buffer
AbortController
queueMicrotask
WebAssembly
setTimeout
setInterval
setImmediate
clearTimeout
clearInterval
clearImmediate
URL
URLSearchParams
MessageChannel
MessageEvent
MessagePort
Event
EventTarget
TextDecoder
TextEncoder
Модульные переменные
__dirname
__filename
exports - это алиас для module.exports
module
require()
Отличия Event Emitter от Event Target
Event Emitter (предпочтительнее для использования)
Берется из модуля events
Несколько lisener на 1 событие
Полностью эмулирует Event Emitter из браузера
Обработка ошибок через error
Встроенные события add / remove listeners
Event Target
Глобальная переменная
Только 1 listener на событие
Частично эмулирует API браузера
Нет обработки через error
Нет событий добавления и удаления обработчиков
Какие методы есть в Event Emitter
addListener - подписаться
on - подписаться
removeListener - отписаться
off - отписаться
prependListener - добавит листенер в начало очереди эмиттера, и его событие выполнится раньше всех (по дефлоту выполняется в порядке очереди добавления)
prependOnceListener - то же самое что и prependListener, но после выполнения удаляет листенер из эмиттера
removeAllListeners - отписаться от всех листенеров
emit - выполнить событие
once - после первого выполнения событие будет удалено из эмиттера
setMaxListeners - устанавливает максммальное количество листенеров для эмиттера, по дефолту их 10
listenerCount - узнать сколько листенеров находится на одном ивенте
listeners - показывает какие именно функции висят на событии
eventNames - показывает именна событий, которые сейчас повешены на эмиттер
Какие методы есть в Event Target
addEventListener - повесить обработчик
dispatchEvent - выполнить событие, но в качестве аргумента должен быть new Event(“name”), а не просто строка
С10K проблема
В мультитредовых серверах, например на Java, раньше 1 поток (1 поток обслуживал 1 запрос на сервер) примерно занимал 1мб, 10000 потоков - 10 ГБ памяти
Эта проблема была раньше, сейчас же трудности с обработкой например миллиона запросов, так как на это на сервере должно быть 1 ТБ оперативной памяти
Сколько потоков в Node.js?
1 поток и огромный thread pool
Non blocking I/O
Главный поток не блокируется вводом и выводом
Сервер будет продолжать обслуживать запросы
Мы работаем с асинхронным кодом
Event Loop
1) Сначала делается запрос
2) Начинает обрабываться нашим V8
3) Проходит через Node bindings и превращается в C/C++ если надо
4) Потом попадает в Event Queue если это асинхронная операция
5) Если синхронный код, то он попадает сразу в Callstack,
6) Асинхронные операции, которые попали в Callstack, если блокируют поток, то попадают в Worker threads, а отттуда снова в event queue, но только как callback
ФАЗЫ:
0) Выполняется синхронный код
1) timers - смотрит есть ли таймеры которые должны завершиться
2) pending callbacks - коллбеки от системных операций
3) idle, prepare - внутрення фаза реализации libuv, повлиять на неё мы никак не можем
4) poll - обработка собтий i/o (читаем файл, записываем и т.д), читает не все запросы, а только какое-то время, и потом снова возвращается по циклу к этому пункту
5) check - тут только setImmediate
6) close callbacks - будут обработаны все close callbacks, например прервалось соединение с сокетами.
7) exit check
!!! Между каждой фазой вызываются промисы, и process.nextTick()
Что такое setImmediate и какие аргументы принимает?
Отрабатывает сразу после выполнения синхронного кода, примает только функцию. P.S. это не таймер
Как мгновенно отвязать и привязать id таймера
someTimerId.unref()
someTimerId.ref()
Очень редкий кейс применения
Сколько Working Threads в Node?
По умолчанию 4
Можно увеличить до 1024
Раньше было до 128
Это всё ограничения libuv
Каждый тред работает на 1 ядре процессора
Модуль “crypto”
Позволяет работать с шифрованием
pbkdf2 - асинхронно позволяет создать из пароля хеш строку
Как увеличить количество Working Threads ?
process.env.UV_THREADPOOL_SIZE =
Что работает на Working Threads а что на уровня ядра?
Working Threads:
Все файловые операции fs.*
dns.lookup
Pipes (некоторые случаи)
CPU intense tasks
Системные асинхронные выховы на уровне ядра:
TCP/UDP сервер и клиент
Pipes
DNS Resolve
Child process
Модуль “https”
Дает возможность делать запросы по https
Как измерять performance в Node?
1) Если нужно измеритиь кусочек кода:
Сначала ставим метки внутри функции или кода:
performance.mark(“start”)
performance.mark(“end”)
Потом ставим отметку измерения
performance.measure(“some name”, “start”, “end”)
После импортируем перфморманс хук:
const perf_hooks = require(‘perf_hooks’);
Создаем обсервер перформанса из хука:
const performanceObserver = new perf_hooks.PerformanceObserver((items, observer) => {
const entry = items.getEntriesByName(“name of our метка измерения”)[0];
console.log(777, “entry: “, entry);
observer.disconnect();
})
Вызываем обсервер:
performanceObserver.observe({ entryTypes: [“measure”] });
2) Если нужно померять целую функцию, то можем метки не раставлять, а сделать так:
Обернуть нашу функцию в timerify
slow = perf_hooks.performance.timerify(slow);
Вызвать обсервер с entryType: function
performanceObserver.observe({ entryTypes: [“function”] });
Как работать с worker_threads
Worker Threads это аналог WebWorker из браузера
1) Для воркера нужо создать отдельный файл
2) Импортируем const { parentPort, workerData } = require(“worker_threads”)
3) parentPort.postMessage(compute(workerData)) - compute это наша функция рандомная
4) В файле где используем воркер импортируем:
const { Worker } = require(“worker_threads”)
5) И делаем примерно такое:
const compute = (array) => {
return new Promise((resolve, reject) => {
const worker = new Worker(“./worker.js”, {
workerData: {array}
})
worker.on("message", (msg) => resolve(msg)) worker.on("error", (err) => reject(err.name)) worker.on("exit", () => console.log("end")) }) }
Важно: Плохая идея использовать новый воркер на каждый новый запрос, тем самым тебя могут задэдосить
Что такое spawn?
Когда использовать:
Когда вам нужно запустить команду, которая может долго работать и выводить много данных.
Как работает:
spawn запускает команду и позволяет вам читать ее вывод по мере выполнения. Это очень полезно для работы с большими объемами данных или долгосрочными процессами, так как не ограничивает объем вывода.
Пример:
Если нужно запустить команду и обрабатывать ее вывод построчно, как это делают программы ping или tail -f.
const { spawn } = require(‘child_process’);
const child = spawn(‘ls’, [‘-lh’, ‘/usr’]); // Запуск команды ‘ls -lh /usr’
child.stdout.on(‘data’, (data) => {
console.log(stdout: ${data}
);
});
child.stderr.on(‘data’, (data) => {
console.error(stderr: ${data}
);
});
child.on(‘close’, (code) => {
console.log(child process exited with code ${code}
);
});
Что такое exec?
Когда использовать:
Когда вам нужно запустить команду и получить весь ее вывод разом, после завершения выполнения.
Как работает:
exec запускает команду и сохраняет весь ее вывод (stdout и stderr) в буфере. После завершения выполнения команды вы получаете весь вывод сразу. Это удобно для коротких команд с небольшим объемом вывода.
Пример:
Если нужно выполнить команду и получить результат целиком, например cat для чтения небольшого файла или ls для краткого списка файлов.
const { exec } = require(‘child_process’);
exec(‘ls -lh /usr’, (error, stdout, stderr) => {
if (error) {
console.error(exec error: ${error}
);
return;
}
console.log(stdout: ${stdout}
);
console.error(stderr: ${stderr}
);
});
Чем отличаются fork, spawn и exec от worker_threads?
Лучше всегда использовать woker, так как это современный подход. Раньше в Node был только fork. Произовдительность в woker при передаче больших файлов намного выше. Все новые библиотеки переписываются с fork на worker threads
fork, spawn и exec:
Создают отдельные процессы с полной изоляцией.
Используются для выполнения внешних команд и скриптов, например написанных не на JS.
Процессы не делят память, что делает их более защищенными, но менее эффективными в обмене данными.
worker_threads:
Создают потоки внутри одного процесса.
Используются для параллельных вычислений на JavaScript с быстрым обменом данными.
Потоки делят память, что позволяет эффективный и быстрый обмен данными, но требует осторожности для предотвращения проблем с доступом к общей памяти.
Что такое fork?
Создет отдельный процесс
Основные отличия и преимущества fork над spawn и exec:
IPC (Inter-Process Communication):
fork автоматически устанавливает канал для межпроцессного взаимодействия (IPC) между родительским и дочерним процессами. Это упрощает обмен сообщениями.
spawn также может быть использован для создания дочерних процессов, но настройка канала IPC и обмен сообщениями требует дополнительных усилий и кода.
Оптимизация для Node.js:
fork специально оптимизирован для запуска новых процессов Node.js. Он автоматически наследует родительские переменные окружения и позволяет легко управлять выполнением Node.js скриптов.
spawn более универсален и используется для запуска любых команд или скриптов. Хотя он может запускать Node.js процессы, fork делает это более эффективно и с меньшими усилиями для разработчика.
peerDependencies
peerDependencies — зависимость, которую не устанавливает ваш пакет автоматически, а ожидает, что её установит сам разработчик проекта.
Используется, чтобы избежать конфликтов версий и обеспечить совместимость.
Когда использовать?
Ваш пакет — это плагин, библиотека компонентов или расширение.
Зависимость должна быть одной для всего проекта (например, React, Vue, Angular).
Пример: React-компоненты или Webpack-плагины.
Почему не dependencies?
Избегает двойных версий (например, двух React в node_modules).
Дает пользователю контроль над версией зависимости.
Предотвращает ошибки, связанные с несовместимостью (например, “Invalid Hook Call”).
npx install-peerdeps my-library
Переменная process
process — это встроенный объект в Node.js, который предоставляет информацию о текущем процессе выполнения и позволяет взаимодействовать с операционной системой. Он всегда доступен без необходимости импорта.
process.argv — это массив, который содержит аргументы командной строки, переданные скрипту. Первый элемент — путь к интерпретатору Node.js, второй — путь к исполняемому файлу скрипта, остальные — аргументы, указанные в командной строке.
node script.js arg1 arg2
[‘/path/to/node’, ‘/path/to/script.js’, ‘arg1’, ‘arg2’]
process.env - объект содержащий переменные окружения.
Используется для хранения конфиденциальной информации (например, API-ключей, паролей) и настройки приложения. Важно: Никогда не коммитьте .env в репозиторий — добавьте его в .gitignore.
Модуль “os”
homedir - возвращает строку домашней директории
Модуль “path”
join - из двух строк делает путь, а не прочто конкатенирует
basename - базовое название файла
extname - название расирения файла
relative - говорит что нам нужно сделать что прийти от from до to, принимает 2 аргумента
isAbsolute - вернет true если путь абсолютный
resolve - принимает аргумент шага (.. или .), выполняет действия относительно текущей папки исполнения
sep - возвращает сепаратор текущей операционной системы