Каков наилучший способ передачи общих переменных в отдельные модули в Node.js?

Я использую отдельные файлы маршрутизатора в качестве модулей для основного приложения и приложения auth. Я не могу получить лучший способ передать переменные (db-клиент) в маршрутизаторы. Я не хочу его жестко кодировать или передавать с помощью:

module.exports = function(app, db) {

Может быть, это лучший способ использовать регистр singleton или использовать глобальную переменную db?

Что вы испытываете с шаблонами дизайна? Какой способ является лучшим и почему?

Ответ 1

Я нашел использование инъекции зависимости, чтобы передать вещи, чтобы быть лучшим стилем. Это действительно выглядело бы так, как будто у вас есть:

// App.js
module.exports = function App() {
};

// Database.js
module.exports = function Database(configuration) {
};

// Routes.js
module.exports = function Routes(app, database) {
};

// server.js: composition root
var App = require("./App");
var Database = require("./Database");
var Routes = require("./Routes");
var dbConfig = require("./dbconfig.json");

var app = new App();
var database = new Database(dbConfig);
var routes = new Routes(app, database);

// Use routes.

Это имеет ряд преимуществ:

  • Это заставляет вас разделить вашу систему на компоненты с явными зависимостями, вместо того, чтобы скрывать зависимости где-то в середине файла, где они называют require("databaseSingleton") или хуже, global.database.
  • Это делает модульное тестирование очень простым: если я хочу изолировать Routes, я могу ввести его поддельными параметрами app и database и протестировать только сам код Routes.
  • Он объединяет все ваши проводки с объектным графом в одном месте, а именно корневой состав (который в этом случае является server.js, точкой входа в приложение). Это дает вам одно место, чтобы посмотреть, как все вписывается в систему.

Одно из лучших объяснений этого, что я видел, - это интервью с Марком Симаном, автор отличной книги Injection Dependency in.NETя > . Он применим так же, как и JavaScript, и особенно к Node.js: require часто используется как классический сервисный локатор вместо простой системы модулей.

Ответ 2

Я предлагаю вам создать файл настроек с экземпляром db и другими вещами, которые вам нужно использовать глобально, как "singleton".

Например, у меня есть settings.js с моим клиентом redis db:

var redis = require('redis');
exports.redis = redis.createClient(6379, '127.0.0.1');

И в других нескольких модулях я включаю его:

var settings = require('./settings');
setting.redis.<...>

Много времени, включая его, у меня всегда есть один экземпляр соединения db.

Ответ 3

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

В этом ответе перечислены некоторые из них. Я также создал упрощенную схему DI здесь.

РЕДАКТИРОВАТЬ: ниже - это копия формы ответа в случае изменения страницы


require способ управления зависимостями в Node.js, и, безусловно, он интуитивно понятен и эффективен, но он также имеет свои ограничения.

Мой совет - взглянуть на некоторые из контейнеров для инъекций Dependency, доступных сегодня для Node.js, чтобы иметь представление о том, каковы их плюсы и минусы. Некоторые из них:

Просто, чтобы назвать несколько.

Теперь реальный вопрос: что вы можете достичь с помощью контейнера Node.js DI, по сравнению с простым require?

Плюсы:

  • лучшая тестируемость: модули принимают свои зависимости в качестве входных данных
  • Inversion of Control: выберите способ подключения ваших модулей, не касаясь основного кода вашего приложения.
  • настраиваемый алгоритм для решения модулей: зависимости имеют "виртуальные" идентификаторы, обычно они не привязаны к пути в файловой системе.
  • Улучшенная расширяемость: включена IoC и "виртуальными" идентификаторами.
  • Возможны другие причудливые вещи:
    • Асинхронная инициализация
    • Управление жизненным циклом модуля
    • Расширяемость самого контейнера DI
    • Может легко реализовать абстракции более высокого уровня (например, АОП)

Минусы:

  • В отличие от Node.js "опыта": не используя require, определенно кажется, что вы отклоняетесь от образа мышления Node.
  • Отношения между зависимостью и ее реализацией не всегда явны. Зависимость может быть разрешена во время выполнения и под влиянием различных параметров. Код становится более сложным для понимания и отладки
  • Более медленное время запуска
  • Зрелость (на данный момент): ни один из текущих решений не является действительно популярным на данный момент, поэтому не так много обучающих программ, не экосистемы, а не битвы.
  • Некоторые контейнеры DI не будут хорошо воспроизводиться с такими модулями, как Browserify и Webpack.

Ответ 4

Он полностью устарел, но вы можете использовать global в script:

 global.foo = new Foo();

в другом script:

 foo.bar();

Вы также можете использовать уже существующую константу:

 Object.foo = new Foo();

И здесь:

 Object.foo.bar();