web-dev-qa-db-fra.com

Quelle est la meilleure façon de passer des variables communes dans des modules séparés dans Node.js?

J'utilise des fichiers de routeur séparés en tant que modules pour l'application principale et l'application d'authentification. Je ne peux pas obtenir le meilleur moyen de transmettre des variables (client db) aux routeurs. Je ne veux pas le coder en dur ou le transmettre avec:

module.exports = function(app, db) {

Peut-être que c'est la meilleure façon d'utiliser le registre singleton ou d'utiliser la variable db globale?

Quelle est votre expérience avec les modèles de conception? Quelle est la meilleure et pourquoi?

59
Serg

J'ai trouvé que l'injection de dépendances, pour transmettre des choses, était le meilleur style. Cela ressemblerait en effet à quelque chose comme vous:

// 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.

Cela présente un certain nombre d'avantages:

  • Cela vous oblige à séparer votre système en composants avec des dépendances claires, au lieu de cacher les dépendances quelque part au milieu du fichier où ils appellent require("databaseSingleton") ou pire, global.database.
  • Cela rend les tests unitaires très faciles: si je veux tester Routes isolément, je peux l'injecter avec de faux paramètres app et database et ne tester que les Routes code lui-même.
  • Il rassemble tous vos câbles d'objets graphiques en un seul endroit, à savoir la racine de composition (qui dans ce cas est server.js, Le point d'entrée de l'application). Cela vous donne un endroit unique pour voir comment tout s'emboîte dans le système.

L'une des meilleures explications que j'ai vues à ce sujet est ne interview de Mark Seeman , auteur de l'excellent livre Injection de dépendances dans .NET. Il s'applique tout autant à JavaScript, et en particulier à Node.js: require est souvent utilisé comme localisateur de service classique, au lieu d'un simple système de modules.

108
Domenic

Je vous suggère de créer un fichier de paramètres avec une instance db et avec d'autres choses que vous devez utiliser globalement comme 'singleton'.

Par exemple, j'ai settings.js avec mon client redis db:

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

Et dans d'autres modules multiples, je l'inclus:

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

Plusieurs fois, y compris, j'ai toujours une instance de connexion db.

2
akaravashkin

Vous pouvez vous sauver tout le code passe-partout du câblage de vos modules si vous utilisez un framework d'injection de dépendances

Cette réponse en répertorie quelques-uns. J'ai également construit un cadre DI plus simple ici .

EDIT: ci-dessous est une copie de la réponse au cas où cette page changerait


require est la manière de gérer les dépendances dans Node.js et elle est sûrement intuitive et efficace, mais elle a aussi ses limites.

Mon conseil est de jeter un œil à certains des conteneurs d'injection de dépendance disponibles aujourd'hui pour Node.js pour avoir une idée de leurs avantages/inconvénients. Certains d'entre eux sont:

Juste pour en nommer quelques-uns.

Maintenant, la vraie question est, que pouvez-vous réaliser avec un conteneur DI Node.js, comparé à un simple require?

Avantages:

  • meilleure testabilité: les modules acceptent leurs dépendances en entrée
  • Inversion de contrôle: décidez comment câbler vos modules sans toucher au code principal de votre application.
  • un algorithme personnalisable pour résoudre les modules: les dépendances ont des identifiants "virtuels", généralement ils ne sont pas liés à un chemin sur le système de fichiers.
  • Meilleure extensibilité: activée par l'IoC et les identifiants "virtuels".
  • Autres trucs fantaisistes possibles:
    • Initialisation asynchrone
    • Gestion du cycle de vie des modules
    • Extensibilité du conteneur DI lui-même
    • Peut facilement implémenter des abstractions de niveau supérieur (par exemple AOP)

Inconvénients:

  • Différent de l '"expérience" Node.js: ne pas utiliser require donne vraiment l'impression de dévier de la façon de penser Node.
  • La relation entre une dépendance et son implémentation n'est pas toujours explicite. Une dépendance peut être résolue au moment de l'exécution et influencée par divers paramètres. Le code devient plus difficile à comprendre et à déboguer
  • Temps de démarrage plus lent
  • Maturité (pour le moment): aucune des solutions actuelles n'est vraiment populaire pour le moment, donc pas tellement de tutoriels, pas d'écosystème, pas de test de combat.
  • Certains conteneurs DI ne fonctionneront pas bien avec des regroupeurs de modules comme Browserify et Webpack.
1
Gaafar

Il est complètement obsolète, mais vous pouvez utiliser global dans un script:

 global.foo = new Foo();

dans un autre script:

 foo.bar();

Vous pouvez également utiliser une constante déjà existante:

 Object.foo = new Foo();

Et ici :

 Object.foo.bar();
0
Vinz243