✨🐢 NodeJS 2024 🚀✨

0.0(0)
studied byStudied by 2 people
learnLearn
examPractice Test
spaced repetitionSpaced Repetition
heart puzzleMatch
flashcardsFlashcards
Card Sorting

1/58

encourage image

There's no tags or description

Looks like no tags are added yet.

Study Analytics
Name
Mastery
Learn
Test
Matching
Spaced

No study sessions yet.

59 Terms

1
New cards

В чем заключается проблема толстых контролеров?

Проблема "толстых контроллеров" заключается в том, что они берут на себя слишком много обязанностей, включая бизнес-логику, обработку ошибок, валидацию данных и взаимодействие с базой данных. Это ведет к плохой читаемости, сложности в поддержке и тестировании.

Решение — разделение логики на слои (например, сервисы, репозитории) и использование middleware для валидации.

2
New cards

Приведите примеры протекания абстракций (типичных для ноды)

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

Пример: работа с потоками в Node.js. В некоторых случаях вам нужно управлять низкоуровневыми деталями, такими как пауза и возобновление потоков, хотя это должно быть скрыто.

readStream.on('data', (chunk) => {
    console.log(`Received ${chunk.length} bytes of data.`);
    readStream.pause(); // Принудительно управляем потоком
    // Как только обработали кусок данных
    setTimeout(() => readStream.resume(), 1000); // Возобновляем поток
});

3
New cards

Чем отличается requre от import в node js в деталях?

В Node.js существует два способа импорта модулей: require и import. Они работают немного по-разному, и их использование связано с различиями между CommonJS и ECMAScript Modules (ESM). Давайте рассмотрим детально основные отличия.

1. Система модулей: CommonJS vs ECMAScript Modules (ESM)

  • require — это часть спецификации CommonJS, которая исторически использовалась в Node.js с момента его создания. CommonJS — это модульная система, которая была разработана для серверного JavaScript до появления официальных ECMAScript модулей.

  • import — это часть стандарта ECMAScript Modules (ESM), который является официальной спецификацией для модулей в JavaScript. Этот стандарт был добавлен в язык в ES6 (ES2015) и поддерживается в современных версиях Node.js.

2. Синхронность vs Асинхронность

  • require загружает модули синхронно. Это значит, что модуль будет загружен и выполнен немедленно во время вызова require. Для серверных приложений это обычно не является проблемой, так как модули часто загружаются один раз при запуске приложения.

  • import работает асинхронно. Он позволяет загружать модули в фоновом режиме, что может быть полезно в клиентских приложениях или при работе с динамическими импортами, где важна производительность и необходимость уменьшения времени загрузки.

3. Обработка модулей

  • require загружает модули во время выполнения программы. То есть, каждый раз, когда вызывается require, Node.js загружает и кэширует модуль.

  • import используется в модульной системе ECMAScript, которая использует строгий статический анализ. Это значит, что import модули определяются во время компиляции и могут быть анализированы на этапе компиляции, что делает их использование более предсказуемым и структурированным.

4. Динамическая загрузка

  • require можно вызывать в любое время, где угодно в коде. Это позволяет динамически загружать модули, основываясь на условиях.

  • import в базовом виде работает только на верхнем уровне файла и не может быть использован динамически. Однако динамическую загрузку можно выполнить с помощью import(), что возвращает промис и позволяет загружать модули динамически:

5. Кэширование

  • Оба метода кэшируют модули, однако кэширование в require происходит на уровне одного экземпляра. То есть, если один модуль был загружен с помощью require, все последующие запросы к этому модулю получат закэшированную версию.

  • import также кэширует модули, но кэшируется промис, что обеспечивает асинхронность загрузки.

6. Экспорт и импорт модулей

  • При использовании require, модули экспортируются через module.exports или exports, а импортируются через const moduleA = require('./moduleA').

7. Поддержка в Node.js

  • require поддерживается во всех версиях Node.js, так как это изначальная система модулей.

  • import изначально не поддерживался в Node.js, но начиная с версии 12, Node.js добавил поддержку ECMAScript модулей. Для использования import в старых версиях Node.js требовалась установка флага --experimental-modules, а также нужно было использовать расширение .mjs или указывать "type": "module" в файле package.json.

8. Именование файлов

  • Файлы CommonJS модулей могут иметь расширение .js и использовать require.

  • Для файлов ECMAScript модулей может использоваться расширение .mjs, либо если указать "type": "module" в package.json, можно использовать расширение .js.

4
New cards

Зачем нам следующие поля Error: error.cause, error.code, error.message, error.stack?

  • error.message: сообщение об ошибке, описывающее проблему.

  • error.stack: трассировка стека, которая показывает, где возникла ошибка.

  • error.code: код ошибки для идентификации типа ошибки.

  • error.cause: дополнительная информация о причине ошибки (вложенные ошибки).

5
New cards

Что можно сделать с for await на экземпляре request:

IncomingMessage?

Использование for await на экземпляре IncomingMessage позволяет асинхронно итерировать по кускам данных, которые приходят в потоке ответа. Это упрощает обработку данных без необходимости вручную добавлять обработчики событий data и end.

6
New cards

. Как Node.js нативно хэширует пароли и в каких случаях нам нужны внешние зависимости для этого?

Node.js предоставляет нативный модуль crypto, который можно использовать для хэширования паролей, но он не предоставляет готовых решений для работы с алгоритмами вроде bcrypt, которые часто используются для хэширования паролей.

Для простого хэширования можно использовать алгоритмы sha256 или pbkdf2, встроенные в crypto, но для более безопасного хэширования, особенно с солью, лучше использовать внешние библиотеки, такие как bcrypt или argon2.

7
New cards

Когда можно использовать синхронные версии файловых операций из node:fs вместо асинхронных, и на что нужно обратить внимание при принятии такого решения?

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

Важные моменты:

  • Использование синхронных операций блокирует весь поток и снижает производительность.

  • Синхронные операции допустимы только в однопоточных сценариях или при инициализации, чтобы избежать задержек в основном потоке.

8
New cards

Предложите лучшие практики для обработки ошибок в асинхронном коде.

  • Использование try/catch в асинхронных функциях для перехвата ошибок.

  • Обработка ошибок на уровне промисов с помощью .catch().

  • Никогда не игнорировать ошибки в асинхронных операциях.

  • Использование глобальных обработчиков необработанных ошибок, таких как process.on('uncaughtException') и process.on('unhandledRejection'), для отслеживания неожиданных ошибок.

  • Разделение ошибок на уровни (например, ошибки валидации, ошибки сети) для корректной обработки.

9
New cards

Как могут появляться уязвимости в проектах на Node.js? Объясните одну из следующих на выбор: XSS, Path traversal, SQL injection, CSRF. Как предотвратить их?

Path traversal (обход путей) — это уязвимость, которая позволяет злоумышленнику получить доступ к файлам за пределами разрешенной директории, манипулируя переменными файлового пути.

Предотвращение:

  • Использовать безопасные методы работы с путями, такие как path.join() и path.resolve(), чтобы избегать неконтролируемых путей.

  • Ограничить доступ к разрешенным файлам с помощью белых списков.

10
New cards

Почему нужно делать return await внутри асинхронных функций и методов, а не возвращать промис?

Использование return await необходимо, чтобы явно дождаться завершения промиса внутри функции. Это позволяет обработать ошибки с помощью блока try/catch.

async function fetchData() {
    try {
        return await someAsyncOperation(); // Ошибка будет обработана здесь
    } catch (error) {
        console.error('Error:', error);
    }
}

Если вернуть промис напрямую (return someAsyncOperation();), ошибки могут не быть пойманы блоком try/catch, что приведет к неопределенному поведению в обработке ошибок.

11
New cards

Почему middleware является антипаттерном? И как писать без него?

Middleware не всегда является антипаттерном, но его чрезмерное использование может привести к "лавине" вызовов, усложняющей код и его отладку. Особенно это касается глобальных middleware, которые могут затруднить понимание, какие логики и где применяются.

Альтернатива:

  • Использование четко разделенных сервисов или контроллеров.

  • Явная инъекция зависимостей и прямые вызовы нужных методов вместо глобальных обработчиков.

12
New cards

Зачем нужен AbortController? Приведите примеры API, где он используется.

AbortController позволяет отменять асинхронные операции, такие как HTTP-запросы или операции ввода-вывода.

const controller = new AbortController();
const signal = controller.signal;

fetch('https://example.com', { signal })
    .then(response => response.json())
    .catch(err => {
        if (err.name === 'AbortError') {
            console.log('Fetch aborted');
        }
    });

controller.abort(); // Прерывание запроса

13
New cards

Как могут утечь все соединения из пула конекшенов к базе данных и как это предотвратить?

Соединения могут "утечь", если приложение открывает соединения и не закрывает их корректно. Это может произойти из-за забытых вызовов connection.close() или при неправильной обработке ошибок.

Предотвращение:

  • Использование connection pooling (пул соединений), чтобы повторно использовать открытые соединения.

  • Грамотное управление временем жизни соединений.

  • Использование тайм-аутов для соединений, чтобы автоматически закрывать долго неактивные соединения.

14
New cards

В чем преимущество async/await и промисов перед callback в ноде? Где невозможно обойтись без callback?

Преимущества async/await и промисов перед коллбэками:

  • Читаемость: Async/await и промисы делают код линейным и легко читаемым, что упрощает понимание и отладку. Коллбэки, наоборот, приводят к сложной вложенности (коллбэк-аду).

  • Обработка ошибок: В промисах ошибки обрабатываются через .catch(), а в async/await можно использовать try/catch, что делает работу с ошибками более понятной по сравнению с вложенными коллбэками.

  • Композиция: Промисы легче комбинировать, используя методы вроде Promise.all(), что затруднительно с коллбэками.

Когда коллбэки все еще необходимы:

  • Обратная совместимость: Многие старые API Node.js до сих пор используют коллбэки.

  • Событийно-ориентированные модели: В некоторых случаях, например, при использовании событийного механизма (как в EventEmitter), коллбэки являются более естественным подходом.

  • Функции обратного вызова в сторонних библиотеках, которые могут вызывать события или динамические коллбэки.

15
New cards

Что делать, если в двух частях одного приложения вам нужны разные версии npm зависимостей?

Если в приложении нужны разные версии одной и той же зависимости, можно использовать:

  1. Монорепозитории с использованием Lerna или Yarn Workspaces: Позволяют управлять разными версиями зависимостей в подмодулях (пакетах) одного репозитория.

  2. Установка зависимостей на уровне подпакетов: Внутри одного проекта можно создавать отдельные пакеты, каждый со своими зависимостями и версией библиотек в package.json.

  3. Использование scoped-пакетов или yarn resolutions: Определенные инструменты, такие как Yarn, позволяют указать в конфигурации resolutions, какая версия пакета должна быть установлена для определенного модуля.

16
New cards

Чем может быть опасно, если зависимость патчит глобальные объекты, классы и прототипы?

Опасности:

  • Конфликты: Если несколько зависимостей изменяют глобальные объекты, это может привести к неожиданным конфликтам и поломкам кода.

  • Трудности с отладкой: Изменение глобальных объектов делает код менее предсказуемым и усложняет отслеживание проблем.

  • Несовместимость с будущими версиями: Обновление Node.js или других зависимостей может сломать патч, что приведет к проблемам с совместимостью.

17
New cards

Для чего нам WebSocket, почему в 2023 брать socket.io плохой вариант и что брать для WebSocket?

WebSocket нужен для обеспечения двусторонней связи между клиентом и сервером в режиме реального времени (например, для чатов, игр или уведомлений).

Почему не стоит брать socket.io в 2023:

  • socket.io использует "фоллбеки" на другие транспортные протоколы, если WebSocket недоступен, что добавляет ненужную сложность.

  • Нативный WebSocket API в Node.js уже достаточно развит, и его использование более производительно и проще.

Альтернатива:

  • Использование встроенного WebSocket API (например, в библиотеке ws для Node.js). Это дает более прямой доступ к WebSocket-протоколу без фоллбеков и лишней логики.

18
New cards

Что дает флаг --watch?

Флаг --watch позволяет Node.js автоматически перезапускать процесс при изменении файлов в проекте. Это полезно при разработке, так как отпадает необходимость вручную перезапускать сервер после каждого изменения.

19
New cards

Чего не хватает в ESM, но есть (поддерживается) в CJS?

Несмотря на то, что ES-модули (ESM) становятся стандартом, есть несколько функций, которые поддерживаются в CommonJS (CJS), но отсутствуют или ограничены в ESM:

  • Динамическая загрузка модулей:

    • В CJS можно динамически загружать модули с помощью require().

    • В ESM загрузка модулей через import() возможна, но она всегда асинхронная и работает через промисы, что добавляет сложности для синхронного кода.

  • Обработка циклических зависимостей:

    • CJS может обрабатывать циклические зависимости между модулями. ESM тоже поддерживает циклические зависимости, но их поведение может быть менее предсказуемым и более сложным в отладке.

  • Возможность условной загрузки модулей:

    • В CJS можно использовать конструкции вроде if (condition) { require('module') }.

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

  • Мутация экспорта:

    • В CJS можно изменять экспортированные значения после их инициализации.

    • В ESM экспорты являются неизменяемыми, и такая возможность отсутствует.

  • Кэширование модулей:

    • Оба типа модулей кэшируются, но require в CJS может быть перезаписан вручную, что позволяет удалять модули из кэша и загружать их заново, тогда как в ESM этого сделать нельзя напрямую.

20
New cards

Почему Node.js не однопоточный? Докажите, что даже не был однопоточным.

Хотя основной поток исполнения в Node.js однопоточный, сама платформа использует несколько потоков под капотом для выполнения операций ввода-вывода, работы с файлами и сетевыми запросами.

Доказательство:

  • libuv: Node.js использует библиотеку libuv, которая управляет пулом потоков для выполнения асинхронных операций (например, файловые операции). Этот пул потоков (обычно 4 по умолчанию) делает Node.js многопоточной на уровне низкоуровневых операций.

  • worker_threads: С версии Node.js 10.5 можно явно создавать потоки (workers), что позволяет параллельно выполнять тяжелые вычисления в отдельных потоках.

21
New cards

Как связаны node:async_hooks и AsyncLocalStorage?

AsyncLocalStorage — это высокоуровневый API для работы с контекстом асинхронного выполнения. Он построен на базе async_hooks, низкоуровневого API для отслеживания всех асинхронных операций в Node.js.

  • AsyncLocalStorage предоставляет более удобный интерфейс для сохранения и получения данных в рамках одного контекста выполнения (например, отслеживания запроса пользователя).

  • async_hooks позволяет детально отслеживать создание, завершение и передачу контекстов между асинхронными вызовами.

22
New cards

Какие в ноде встроенные средства сериализации аналогичны JSON только для бинарной сериализации?

Node.js имеет встроенные средства для работы с бинарной сериализацией данных:

  1. Buffer — основное средство для работы с бинарными данными. Можно использовать для чтения и записи байтов.

  2. node:buffer (Buffer API): Предоставляет API для создания и управления бинарными данными. Используется в сетевых приложениях и при работе с файлами.

  3. v8.serialize / v8.deserialize: Инструменты для бинарной сериализации данных в формате, аналогичном JSON, но для бинарных данных, что делает их более эффективными для передачи больших объектов.

23
New cards

. Как следить за изменениями файлов и директорий на диске и какие с этим могут возникать проблемы?

Для отслеживания изменений в файлах и директориях можно использовать:

  1. fs.watch — отслеживает изменения в файлах или директориях.

  2. fs.watchFile — периодически проверяет файл на изменения (polling).

  3. chokidar — популярная внешняя библиотека, которая более надежно обрабатывает события файловой системы.

Проблемы:

  • Кросс-платформенные отличия: Поведение fs.watch может различаться между операционными системами, особенно на Windows и Linux.

  • Высокая нагрузка на CPU: Наблюдение за множеством файлов может значительно нагрузить процессор.

  • Некорректная работа с большими директориями: На больших директориях fs.watch может не срабатывать на каждый файл.

24
New cards

Чем заменить deprecated fs.exists и почему его выпиливают из ноды?

fs.exists был признан устаревшим, потому что его использование было неочевидным и приводило к race conditions. Вместо этого рекомендуется использовать:

fs.access — проверяет доступность файла или директории с учетом прав доступа.

Промисифицированная версия fs.promises.access для асинхронного использования.

25
New cards

. Что такое back pressure для стримов и какая проблема была бы без него?

Back pressure — это механизм, который управляет потоком данных между источником (например, чтение из файла) и приемником (например, запись в другой файл или отправка по сети) в случае, если приемник не успевает обрабатывать данные с той же скоростью, с которой их отправляет источник.

Без back pressure:

  • Приемник мог бы быть перегружен, что привело бы к утечке памяти или краху приложения.

Пример:

В Node.js, когда запись в поток слишком медленная, поток автоматически переходит в режим ожидания, чтобы источник данных мог замедлиться.

26
New cards

Докажите, что любой модуль в ноде при загрузке оборачивается в функцию и создает замыкание?

В Node.js каждый модуль фактически оборачивается в функцию при его загрузке. Это означает, что переменные и функции, определенные в модуле, замкнуты в своем собственном пространстве имен и недоступны извне, что предотвращает конфликт имен

27
New cards

Где в ноде используется паттерн Revealing Constructor (открытый конструктор, есть много таких мест)?

Паттерн Revealing Constructor заключается в том, что объект создается с приватными переменными, которые становятся доступными через методы, раскрытые конструктором. Этот паттерн часто используется в модулях Node.js для инкапсуляции данных и предоставления определенного API.

Примеры:

  • http.Server: Конструктор http.Server создает объект сервера с внутренними свойствами, к которым доступ возможен только через методы, такие как listen, close, и обработчики событий.

  • crypto.Cipher и crypto.Decipher: Эти классы скрывают внутренние детали шифрования/дешифрования, предоставляя методы, которые раскрываются через конструктор.

Этот паттерн позволяет скрыть внутреннюю логику и предотвращает прямой доступ к приватным свойствам.

28
New cards

Как сделать переопределение write для экземпляра Writable без создания класса наследника?

Можно переопределить метод write для экземпляра Writable без создания подкласса, просто присвоив новый метод для конкретного объекта.

29
New cards

В чем причина медленных вызовов из JavaScript кода к аддонам на C, C++ или подключенных через N-API?

Причины медленных вызовов из JavaScript в C/C++ через N-API:

  1. Cost of Context Switching: Вызов из JavaScript в C/C++ требует переключения контекста между движком V8 и машинным кодом, что создает накладные расходы.

  2. Marshalling Data: Когда данные передаются между JavaScript и C++, необходимо выполнить сериализацию и десериализацию данных, что также добавляет задержки.

  3. Garbage Collection: Проблемы могут возникнуть из-за частых операций с памятью, которые инициируют сборку мусора в V8.

Чтобы минимизировать эти проблемы, важно оптимизировать вызовы так, чтобы минимизировать количество переходов между языками и избегать частых операций с большими объемами данных.

30
New cards

Что такое MessagePort и BroadcastChannel?

MessagePort: Часть API worker_threads, которая используется для передачи сообщений между потоками. Два объекта MessagePort могут связываться между собой для передачи данных асинхронно через сообщения.

BroadcastChannel: API для передачи сообщений между разными контекстами выполнения, например, между разными Worker'ами или основным потоком. Все подписчики на один канал будут получать сообщения.

31
New cards

Чем отличаются fs.stat, fs.fstat, fs.lstat?

  • fs.stat: Получает информацию о файле или директории по пути. Следует символическим ссылкам, возвращая информацию о реальном файле.

  • fs.fstat: Получает информацию о файле, используя файловый дескриптор (fd). Используется для работы с уже открытыми файлами.

  • fs.lstat: Похож на fs.stat, но не следует символическим ссылкам, возвращая информацию о самой ссылке.

32
New cards

Какие вы знаете deprecated API и какова стратегия их вывода из употребления?

Некоторые известные устаревшие API в Node.js:

  1. fs.exists: Удален в пользу fs.access, так как его поведение могло приводить к race conditions.

  2. require.extensions: Устаревший механизм для изменения поведения require(). Заменен на другие механизмы загрузки модулей.

  3. process.EventEmitter: Заменен на events.EventEmitter.

Стратегия вывода из употребления:

  • Сначала API помечается как устаревший, что выводится в консоль в виде предупреждения.

  • После нескольких мажорных релизов API может быть полностью удален.

  • Разработчикам предоставляется достаточно времени на миграцию к альтернативам.

33
New cards

Объясните, как можно написать (или напишите) адаптеры асинхронности promisify и callbackify?

promisify — это адаптер, который преобразует функцию с коллбэком в функцию, возвращающую промис.

function promisify(fn) {
    return function (...args) {
        return new Promise((resolve, reject) => {
            fn(...args, (err, result) => {
                if (err) return reject(err);
                resolve(result);
            });
        });
    };
}

// Пример использования
const fs = require('fs');
const readFile = promisify(fs.readFile);

readFile('example.txt', 'utf8')
    .then(data => console.log(data))
    .catch(err => console.error(err));
  • callbackify — это адаптер, который преобразует функцию, возвращающую промис, обратно в функцию с коллбэком.

function callbackify(fn) {
    return function (...args) {
        const callback = args.pop();
        fn(...args)
            .then(result => callback(null, result))
            .catch(error => callback(error));
    };
}

// Пример использования
const promiseFn = () => Promise.resolve('data');
const callbackFn = callbackify(promiseFn);

callbackFn((err, result) => {
    if (err) return console.error(err);
    console.log(result);
});

34
New cards

Почему у event loop есть фазы? Почему мало одной очереди?

Event Loop в Node.js разделен на несколько фаз для более эффективной и предсказуемой обработки различных типов операций (таймеры, I/O, callbacks, и т.д.). Каждая фаза отвечает за обработку определенного типа операций, что позволяет:

  • Избежать задержек и "засорения" одной глобальной очереди. Операции с разными приоритетами (например, таймеры и I/O) не конкурируют за обработку.

  • Поддерживать предсказуемый порядок выполнения задач, что важно для асинхронного кода и обратной совместимости.

Одна очередь была бы неэффективной, так как таймеры, I/O операции и коллбэки могли бы блокировать выполнение друг друга.

35
New cards

Чем отличаются микротаски и макротаски?

  • Макротаски (macrotasks) — это крупные задачи, которые включают в себя выполнение основной работы цикла событий (например, setTimeout, I/O операции, сетевые запросы).

    Пример макротаски: setTimeout(), setImmediate(), I/O операции.

  • Микротаски (microtasks) — это задачи с высоким приоритетом, которые выполняются сразу после завершения текущей макротаски, но до начала новой макротаски. Они чаще используются для внутренних процессов движка, таких как обработка промисов.

    Пример микротаски: process.nextTick(), обработка .then() у промисов.

Различие: Микротаски всегда выполняются перед макротасками. Например, промисы всегда будут разрешены до выполнения задач, поставленных через setTimeout.

36
New cards

В чем особенности обработки uncaught exceptions в Node.js?

Если ошибка не поймана в асинхронном коде, она считается uncaught exception и может привести к аварийному завершению процесса. Для обработки таких ошибок можно использовать глобальный обработчик:

process.on('uncaughtException', (err) => {
    console.error('Unhandled exception:', err);
    // Завершение процесса
    process.exit(1);
});

37
New cards

Чем отличаются nextTick, setImmediate и setTimeout?

  • process.nextTick(): Выполняется в конце текущей фазы Event Loop, до того как Event Loop продолжит выполнение следующей фазы. Используется для обработки задач с высоким приоритетом (внутри текущей фазы).

  • setImmediate(): Выполняется на следующем витке Event Loop, после завершения текущей фазы и перед следующими макротасками.

  • setTimeout(): Выполняется после заданной задержки (в миллисекундах). Если задержка установлена в 0, задача выполняется на следующей фазе Event Loop после других макротасков.

38
New cards

Зачем есть ref() и unref() у таймеров, сокетов, серверов и других подобных классов?

  • ref(): Объект (например, таймер или сокет) будет удерживать активный процесс Node.js в работе до тех пор, пока он не завершится.

  • unref(): Объект не будет блокировать завершение программы, если это единственное событие, оставшееся в очереди.

39
New cards

. Почему server.connections сделали deprecated и как теперь получить подключения?

server.connections был устаревшим, так как не работал корректно в случае использования Keep-Alive или с асинхронными операциями. Для получения списка активных подключений лучше использовать события и хранить количество подключений вручную:

40
New cards

Перечислите основные случаи, приводящие к утечке памяти и как с этим бороться?

  • Неосвобожденные замыкания: Переменные, замкнутые в функциях, продолжают существовать, даже если они больше не нужны.

    • Решение: Избегать создания ненужных замыканий и очистка объектов после их использования.

  • Глобальные объекты: Объекты, записанные в глобальную область видимости, остаются в памяти.

    • Решение: Использовать переменные локально и избегать глобальных объявлений.

  • Слушатели событий: Слишком много зарегистрированных обработчиков событий, которые не удаляются.

    • Решение: Очищать обработчики через removeListener или использовать once().

  • Кэширование: Неправильное управление кэшом, когда слишком много данных сохраняется в памяти.

    • Решение: Управлять размером кэша и периодически очищать его.

41
New cards

Чем отличается node:cluster и node:child_process? И когда cluster может становиться узким местом?

  • node:child_process: Позволяет создавать новые процессы, которые работают независимо от основного. Можно обмениваться сообщениями через IPC.

    Пример: выполнение тяжелых операций в отдельном процессе.

  • node:cluster: Используется для создания нескольких воркеров, которые могут обрабатывать запросы параллельно. Воркеры разделяют сетевые соединения и часто используются для улучшения производительности HTTP-серверов.

    Узкое место cluster:

    • Поскольку все воркеры делят одно и то же сетевое соединение, производительность может снижаться при большом количестве запросов. В таких случаях лучше использовать балансировщики нагрузки или другие методы распределения нагрузки.

42
New cards

В каких случаях нужно отключать автоматическую сборку мусора и брать ее вызов в свои руки?

В большинстве случаев отключать автоматическую сборку мусора не рекомендуется. Однако, если ваше приложение сталкивается с большими пиками использования памяти (например, работа с большими файлами или буферами), можно вручную вызвать сборку мусора для освобождения памяти между операциями.

if (global.gc) {
    global.gc();
} else {
    console.log('GC not exposed');
}

Для включения ручного управления сборкой мусора запустите Node.js с флагом --expose-gc.

Применение: Используйте ручную сборку мусора для освобождения больших объемов памяти после выполнения крупных задач.

43
New cards

Как сбросить кеш require для определенной библиотеки? Как быть в случае ESM?

Для сброса кэша модуля, загруженного через require, можно удалить его из кэша вручную:

delete require.cache[require.resolve('module-name')];

В случае ESM (ES-модули), кэширование управляется движком V8, и прямого способа сброса кэша через import не существует. Одним из решений может быть перезапуск процесса Node.js, если требуется полная перезагрузка модулей.

44
New cards

Откуда берутся идентификаторы __dirname и __filename, require и import, fetch и Array?

  • __dirname и __filename: Это глобальные переменные, доступные в каждом модуле Node.js. Они предоставляются Node.js и инкапсулируются при загрузке каждого модуля, что создаёт замыкание, включающее эти переменные.

  • require и import: В CommonJS (CJS) require — это встроенная функция загрузки модулей, тогда как import является частью спецификации ES-модулей и реализована в движке V8.

  • fetch: В Node.js fetch появился в последних версиях как часть стандарта Web API, но в браузерах он встроен изначально.

  • Array: Это глобальный встроенный объект JavaScript, предоставляемый самим движком V8 и доступный в любой среде выполнения JavaScript.

45
New cards

. Почему следует отказаться от использования библиотеки node:url?

Библиотека node:url считается устаревшей и менее удобной по сравнению с новыми стандартными Web API, такими как URL, который стал доступен нативно в Node.js. Новый API:

  • Более современный и совместимый с браузерной версией.

  • Предоставляет более мощные и удобные функции для работы с URL.

const myUrl = new URL('https://example.com/path?name=example');
console.log(myUrl.searchParams.get('name')); // 'example'

46
New cards

Чем отличаются cpu-intensive, ram-intensive и io-intensive задачи?

  • CPU-intensive задачи требуют много вычислительных ресурсов процессора.

    • Пример: Расчет больших массивов данных, шифрование, сжатие данных, сложные математические вычисления.

  • RAM-intensive задачи требуют много оперативной памяти.

    • Пример: Обработка больших наборов данных в памяти, работа с большими файлами, кэширование.

  • I/O-intensive задачи требуют много операций ввода-вывода.

    • Пример: Чтение/запись файлов, сетевые запросы, операции с базой данных.

47
New cards

. Почему не нужно использовать process.on('multipleResolves', handler)?

Использование process.on('multipleResolves') может свидетельствовать о том, что есть ошибки в коде, где промис разрешается или отклоняется несколько раз. Хотя этот обработчик позволяет отлавливать такие ошибки, лучше всего решать проблему на уровне кода:

  • Избегать многократного вызова resolve или reject для одного промиса.

  • Исправить логику, которая приводит к таким ситуациям, вместо того чтобы полагаться на обработчик событий.

48
New cards

. Расскажите, на что влияет опция noDelay у серверов, метод setNoDelay у request и socket?

  • setNoDelay(true) отключает алгоритм Nagle, который объединяет маленькие пакеты данных в один большой для оптимизации сети. Отключение этого алгоритма может ускорить отправку данных, если отправляются небольшие куски, такие как интерактивные команды.

  • Когда использовать: Если важно немедленно отправить данные, например, в реальных временных приложениях, таких как онлайн-игры или чаты.

49
New cards

Для чего используется модуль node:perf_hooks? И может ли он работать с воркерами?

Модуль node:perf_hooks используется для измерения производительности внутри Node.js приложений. Он предоставляет API для создания меток времени и сбора данных о производительности.

const { performance } = require('node:perf_hooks');

performance.mark('start');
setTimeout(() => {
    performance.mark('end');
    performance.measure('My Timer', 'start', 'end');
}, 1000);

50
New cards

Что вы думаете про экспериментальное API итерируемых методов (filter, map, reduce...) у стримов?

Экспериментальное API для работы с потоками (stream) с использованием методов, подобных Array (например, filter, map, reduce), — это многообещающая функциональность, которая делает работу с потоками более декларативной и похожей на работу с массивами.

Преимущества:

  • Лаконичный код: Методы map, filter и другие позволяют работать с потоками данных более декларативно, упрощая написание кода и улучшая его читабельность.

  • Унифицированность: Программисты могут использовать уже знакомые методы, которые они используют с массивами, теперь и с потоками.

Недостатки (пока экспериментально):

  • Производительность может быть хуже, чем при использовании низкоуровневых операций.

  • Поскольку API экспериментальное, оно может изменяться в будущих версиях Node.js, что требует осторожности при его использовании в продакшене.

const { Readable } = require('stream');

const readable = Readable.from([1, 2, 3, 4, 5])
    .map(x => x * 2)
    .filter(x => x > 5);

readable.on('data', chunk => {
    console.log(chunk); // 6, 8, 10
});

51
New cards

Какие вы знаете способы интернационализации приложений?

  • i18n библиотеки (например, i18next, node-polyglot):

    • Поддержка динамических переводов.

    • Поддержка множественных языков и локализаций.

    • Пример: переключение между языками в зависимости от предпочтений пользователя.

  • Поддержка через JSON-файлы:

    • Хранение переводов и локализованных строк в отдельных JSON-файлах.

    • Поддержка структуры данных для множественных языков.

  • Использование ICU (International Components for Unicode):

    • Node.js поддерживает ICU для работы с локалями, форматированием чисел, дат и валют через API Intl.

  • Использование внешних API:

    • Интеграция с сервисами для перевода контента, такими как Google Translate или другие коммерческие платформы.

52
New cards

Используете ли вы встроенный test runner и библиотеку

Да, встроенный тест-раннер Node.js, который доступен с версии 18, является легковесным и простым способом для написания модульных тестов. Он полезен для небольших проектов или для быстрого создания тестов без установки внешних библиотек.

Преимущества:

  • assert: Простая встроенная библиотека для проверок в тестах.

  • Test Runner: Интегрированная среда для выполнения тестов без установки внешних библиотек.

53
New cards

Какие вы использовали ключи при запуске ноды?

Некоторые полезные ключи для запуска Node.js:

  1. --inspect и --inspect-brk:

    • Для отладки через DevTools.

    • --inspect-brk останавливает выполнение в начале.

  2. --max-old-space-size:

    • Для увеличения памяти, выделенной V8 (например, для работы с большими объектами или данными).

    • Пример: node --max-old-space-size=4096 server.js.

  3. --trace-warnings:

    • Для вывода стека предупреждений.

  4. --experimental-modules:

    • Для работы с экспериментальными функциями ES-модулей в предыдущих версиях Node.js.

  5. --trace-gc:

    • Для отслеживания работы сборщика мусора, полезно для анализа производительности.

54
New cards

Как сдампить хип процесса и что с ним дальше делать?

Создание дампа памяти:

  • Включить флаг --inspect и использовать DevTools для снятия дампа памяти.

  • Либо использовать пакет node-heapdump для программного создания дампа

55
New cards

Для чего нам модуль, который называется модуль, а именно node:module?

Модуль node:module предоставляет низкоуровневые функции для работы с модулями в Node.js. Он позволяет:

  • Динамически загружать модули.

  • Работать с путями модулей.

  • Управлять кэшем модулей.

56
New cards

Как работать с самоподписанными SSL сертификатами? И в чем ограничение их использования?

57
New cards

Для чего в Node.js есть Web Streams API и в чем разница с node:stream?

Web Streams API был добавлен в Node.js для унификации с API, доступным в браузерах. Это делает работу с потоками более консистентной между серверной и клиентской частью, что облегчает переносимость кода.

Различия с node:stream:

  • Web Streams API ориентирован на совместимость с браузерами и предоставление универсального интерфейса для работы с потоками.

  • Node.js Streams (модуль node:stream) — это низкоуровневый API, специфичный для Node.js, который поддерживает такие режимы, как Readable, Writable, Duplex, и Transform.

Основное отличие заключается в том, что node:stream ориентирован на производительность и поддерживает больше специфичных для Node.js функциональностей, таких как pipe, обработка ошибок и backpressure.

58
New cards

2. Для чего нужны классы Blob и File из node:buffer?

Blob и File — это классы, которые предоставляют универсальный интерфейс для работы с файловыми данными и бинарными данными в Node.js, аналогичный их браузерным версиям.

Blob: Позволяет работать с бинарными данными как с неизменяемыми файлами. Используется для отправки данных в веб-запросах или сохранения файлов.

File: Представляет собой файл и содержит метаданные, такие как имя файла и дата последней модификации.

59
New cards

В чем разница моделей прав доступа module-based и process-based?

  • Module-based model: В этом подходе права доступа контролируются на уровне модулей. Каждому модулю предоставляется набор разрешений на доступ к определенным ресурсам (файловой системе, сети и т.д.). Это позволяет изолировать модули друг от друга и предотвращать несанкционированный доступ.

    Преимущества: Лучшая изоляция и контроль над доступом для каждого модуля.

  • Process-based model: Права доступа задаются на уровне всего процесса. Все модули в процессе разделяют одни и те же права, что делает управление более простым, но менее гибким.

    Преимущества: Простота управления правами на уровне всего процесса, но меньше возможностей для гибкой изоляции.