Ai-je besoin d'une injection de dépendance dans NodeJS, ou comment gérer ...?

je crée actuellement quelques projets expérimentaux avec nodejs. J'ai programmé beaucoup D'applications Web Java EE avec Spring et j'ai apprécié la facilité d'injection de dépendances.

maintenant je suis curieux: comment faire l'injection de dépendance avec noeud? Ou: ai-je besoin? Existe-t-il un concept de remplacement, parce que le style de programmation est différent?

je parle de choses simples, comme le partage d'un objet de connexion de base de données, jusqu'à présent, mais je n'ont pas trouvé une solution qui me satisfait.

167
demandé sur Arjan Tijms 2012-02-12 21:19:47

21 réponses

en bref, vous n'avez pas besoin d'un conteneur d'injection de dépendances ou d'un locater de service comme vous le feriez en C#/Java. Depuis Le Nœud.js, utilise le module pattern , il n'est pas nécessaire d'effectuer l'injection du constructeur ou de la propriété. Bien que vous le pouvez encore.

la grande chose à propos de JS est que vous pouvez modifier à peu près tout pour atteindre ce que vous voulez. C'est pratique quand il s'agit de tester.

Voici mon très boiteux exemple artificiel.

MyClass.js :

var fs = require('fs');

MyClass.prototype.errorFileExists = function(dir) {
    var dirsOrFiles = fs.readdirSync(dir);
    for (var d in dirsOrFiles) {
        if (d === 'error.txt') return true;
    }
    return false;
};

MyClass.test.js :

describe('MyClass', function(){
    it('should return an error if error.txt is found in the directory', function(done){
        var mc = new MyClass();
        assert(mc.errorFileExists('/tmp/mydir')); //true
    });
});

comment MyClass dépend du module fs ? Comme @ShatyemShekhar l'a mentionné, vous pouvez en effet faire l'injection de constructeur ou de propriété comme dans d'autres langues. Mais ce N'est pas nécessaire en Javascript.

Dans ce cas, vous pouvez faire deux choses.

vous pouvez couper la méthode fs.readdirSync ou vous peut retourner un module entièrement différent lorsque vous appelez require .

Méthode 1:

var oldmethod = fs.readdirSync;
fs.readdirSync = function(dir) { 
    return ['somefile.txt', 'error.txt', 'anotherfile.txt']; 
};

*** PERFORM TEST ***
*** RESTORE METHOD AFTER TEST ****
fs.readddirSync = oldmethod;

Méthode 2:

var oldrequire = require
require = function(module) {
    if (module === 'fs') {
        return {
            readdirSync: function(dir) { 
                return ['somefile.txt', 'error.txt', 'anotherfile.txt']; 
            };
        };
    } else
        return oldrequire(module);

}

la clé est de tirer parti de la puissance du noeud.JS et Javascript. Note, je suis un gars en Coffee-script, donc ma syntaxe JS pourrait être incorrecte quelque part. Aussi, je ne dis pas que c'est la meilleure façon, mais c'est une façon. Les gourous Javascript pourraient être en mesure de suivez les autres solutions.

mise à jour:

ceci devrait répondre à votre question spécifique concernant les connexions de base de données. Je créerais un module séparé pour que vous encapsuliez votre logique de connexion à la base de données. Quelque chose comme ceci:

MyDbConnection.js : (assurez-vous de choisir un meilleur nom)

var db = require('whichever_db_vendor_i_use');

module.exports.fetchConnection() = function() {
    //logic to test connection

    //do I want to connection pool?

    //do I need only one connection throughout the lifecyle of my application?

    return db.createConnection(port, host, databasename); //<--- values typically from a config file    
}

alors, n'importe quel module qui a besoin d'une connexion de base de données serait alors juste incluez votre module MyDbConnection .

SuperCoolWebApp.js :

var dbCon = require('./lib/mydbconnection'); //wherever the file is stored

//now do something with the connection
var connection = dbCon.fetchConnection(); //mydbconnection.js is responsible for pooling, reusing, whatever your app use case is

//come TEST time of SuperCoolWebApp, you can set the require or return whatever you want, or, like I said, use an actual connection to a TEST database. 

ne suivez pas cet exemple mot à mot. C'est un exemple boiteux en essayant de communiquer que vous utilisez le module pour gérer vos dépendances. Espérons que cela aide un peu plus.

87
répondu JP Richardson 2012-02-13 18:43:47

require est le façon de gérer les dépendances dans le Nœud.js et sûrement, il est intuitif et efficace, mais il a aussi ses limites.

mon conseil est de jeter un oeil à certains des conteneurs D'Injection de dépendance disponibles aujourd'hui pour le noeud.js avoir une idée sur ce que sont leurs avantages/inconvénients. Certains d'entre eux sont:

pour n'en citer que quelques-uns.

maintenant, la vraie question Est, Que pouvez-vous obtenir avec un noeud.js di container, par rapport à un simple require ?

Pour:

  • meilleure testabilité: les modules acceptent leurs dépendances en entrée
  • Inversion de contrôle: décider comment connecter vos modules sans toucher au code principal de votre application.
  • un algorithme personnalisable pour résoudre des modules: les dépendances ont des identificateurs" virtuels", généralement ils ne sont pas liés à un chemin sur le système de fichiers.
  • mieux extensibilité: activée par le CIO et les identificateurs "virtuels".
  • autre Fantaisie possible:
    • initialisation Async
    • Module de gestion du cycle de vie
    • extensibilité du conteneur DI lui-même
    • peut facilement mettre en œuvre des abstractions de niveau supérieur (par exemple AOP)

Inconvénients:

  • différent du noeud.js "expérience": ne pas utiliser require se sent certainement comme vous déviez de la façon de penser de Noeud.
  • la relation entre une dépendance et sa mise en œuvre n'est pas toujours explicite. Une dépendance peut être résolue à 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é (au the moment): aucune des solutions actuelles n'est vraiment populaire à l'heure actuelle, donc pas tant de tutoriels, pas d'écosystème, pas de combat testé.
  • certains conteneurs DI ne vont pas bien jouer avec les bundlers de module comme Browserify et Webpack.

comme pour tout ce qui concerne le développement de logiciels, le choix entre DI ou require dépend de vos exigences, de votre complexité de système et de votre style de programmation.

63
répondu Mario 2015-09-14 14:22:45

j'ai aussi écrit un module pour accomplir ceci, il s'appelle rewire . Il suffit d'utiliser npm install rewire et ensuite:

var rewire = require("rewire"),
    myModule = rewire("./path/to/myModule.js"); // exactly like require()

// Your module will now export a special setter and getter for private variables.
myModule.__set__("myPrivateVar", 123);
myModule.__get__("myPrivateVar"); // = 123


// This allows you to mock almost everything within the module e.g. the fs-module.
// Just pass the variable name as first parameter and your mock as second.
myModule.__set__("fs", {
    readFile: function (path, encoding, cb) {
        cb(null, "Success!");
    }
});
myModule.readSomethingFromFileSystem(function (err, data) {
    console.log(data); // = Success!
});

j'ai été inspiré par l'injecteur de Nathan MacInnes mais a utilisé une approche différente. Je n'utilise pas vm pour évaluer le module test, en fait j'utilise le propre require de node. De cette façon, votre module se comporte exactement comme en utilisant require() (sauf vos modifications). De plus, le débogage est entièrement supporté.

37
répondu Johannes Ewald 2017-05-23 12:18:21

je sais que ce fil est assez vieux à ce stade, mais je me suis dit que j'allais y réfléchir. Le TL;DR est qu'en raison de la nature dynamique et non typée de JavaScript, vous pouvez en fait faire beaucoup de choses sans avoir recours au modèle d'injection de dépendances (DI) ou en utilisant un cadre DI. Cependant, comme une application devient plus grande et plus complexe, DI peut certainement aider la maintenabilité de votre code.

DI en C#

pour comprendre pourquoi DI N'est pas aussi grand d'un besoin dans JavaScript, il est utile de regarder un langage fortement dactylographié comme C#. (Excuses à ceux qui ne connaissent pas C#, mais il devrait être assez facile à suivre.) Dire que nous avons une application qui décrit une voiture et son klaxon. Vous définiriez deux classes:

class Horn
{
    public void Honk()
    {
        Console.WriteLine("beep!");
    }
}

class Car
{
    private Horn horn;

    public Car()
    {
        this.horn = new Horn();
    }

    public void HonkHorn()
    {
        this.horn.Honk();
    }
}

class Program
{
    static void Main()
    {
        var car = new Car();
        car.HonkHorn();
    }
}

il y a peu de problèmes avec l'écriture du code de cette façon.

  1. la classe Car est étroitement liée à la mise en œuvre particulière de la corne en la classe Horn . Si nous voulons changer le type de klaxon utilisé par la voiture, nous devons modifier la classe Car même si son utilisation du klaxon ne change pas. Cela rend également les tests difficiles car nous ne pouvons pas tester la classe Car indépendamment de sa dépendance, la classe Horn .
  2. la classe Car est responsable du cycle de vie de la classe Horn . Dans un exemple simple comme celui-ci, ce n'est pas un grand problème, mais en réalité les dépendances d'applications auront des dépendances, qui auront des dépendances,etc. La classe Car devrait être responsable de la création de l'arbre entier de ses dépendances. Ce n'est pas seulement compliqué et répétitif, mais il viole la "responsabilité unique" de la classe. Il devrait se concentrer sur le fait d'être une voiture, et non de créer des instances.
  3. il n'y a aucun moyen de réutiliser les mêmes instances de dépendances. Encore une fois, ce n'est pas important dans cette application de jouet, mais envisager une connexion de base de données. Vous avez généralement une instance unique qui est partagée à travers votre application.

maintenant, reformulons ceci pour utiliser un schéma d'injection de dépendance.

interface IHorn
{
    void Honk();
}

class Horn : IHorn
{
    public void Honk()
    {
        Console.WriteLine("beep!");
    }
}

class Car
{
    private IHorn horn;

    public Car(IHorn horn)
    {
        this.horn = horn;
    }

    public void HonkHorn()
    {
        this.horn.Honk();
    }
}

class Program
{
    static void Main()
    {
        var horn = new Horn();
        var car = new Car(horn);
        car.HonkHorn();
    }
}

nous avons fait deux choses clés ici. Tout d'abord, nous avons introduit une interface que notre classe Horn implémente. Cela nous permet de coder la classe Car à l'interface au lieu de l'implémentation particulière. Maintenant le code peut prendre n'importe quoi qui met en œuvre IHorn . Deuxièmement, nous avons pris l'instanciation horn de Car et la passer à la place. Cela résout les problèmes ci-dessus et laisse à la fonction principale de l'application de gérer les instances spécifiques et leurs cycles de vie.

ce qui signifie que cela pourrait introduire un nouveau type de klaxon pour la voiture à utiliser sans toucher la Car classe:

class FrenchHorn : IHorn
{
    public void Honk()
    {
        Console.WriteLine("le beep!");
    }
}

le main pourrait juste injecter une instance de la classe FrenchHorn à la place. Cela simplifie considérablement les tests. Vous pouvez créer une classe MockHorn pour injecter dans le constructeur Car pour vous assurer que vous testez seulement la classe Car en isolation.

l'exemple ci-dessus montre une injection manuelle de dépendance. Typiquement DI est fait avec un cadre (par exemple Unité ou Ninject dans le C# world). Ces cadres feront toute la câblage pour vous en parcourant votre graphique de dépendances et en créant des instances au besoin.

Le Noeud Standard.js Way

regardons maintenant le même exemple dans Node.js. Nous casserions probablement notre code en 3 modules:

// horn.js
module.exports = {
    honk: function () {
        console.log("beep!");
    }
};

// car.js
var horn = require("./horn");
module.exports = {
    honkHorn: function () {
        horn.honk();
    }
};

// index.js
var car = require("./car");
car.honkHorn();

comme JavaScript n'est pas typé, nous n'avons pas le même couplage serré qu'avant. Les interfaces ne sont pas nécessaires (elles n'existent pas non plus) car le module car tentez d'appeler la méthode honk sur n'importe quelle exportation du module horn .

de plus, parce que require de Node cache tout, les modules sont essentiellement des singletons stockés dans un conteneur. Tout autre module qui exécute un require sur le horn module obtiendra la même instance exacte. Cela rend le partage d'objets singleton comme des connexions de base de données très facile.

maintenant, il ya encore la question que la car module est responsable de récupérer sa propre dépendance horn . Si vous voulez que la voiture utilise un module différent pour son klaxon, vous devez changer la déclaration require dans le module car . Ce n'est pas très courant, mais cela pose des problèmes avec les tests.

la façon habituelle dont les gens gèrent le problème de test est avec proxyquire . En raison de la nature dynamique de JavaScript, proxyquire intercepte les appels à require et renvoie tous les talons / moqueries que vous fournissez à la place.

var proxyquire = require('proxyquire');
var hornStub = {
    honk: function () {
        console.log("test beep!");
    }
};

var car = proxyquire('./car', { './horn': hornStub });

// Now make test assertions on car...

C'est plus que suffisant pour la plupart des applications. Si cela fonctionne pour votre application, puis aller avec elle. Cependant, d'après mon expérience, à mesure que les applications prennent de l'ampleur et deviennent plus complexes, il devient plus difficile de conserver un code comme celui-ci.

DI in JavaScript

noeud.js est très flexible. Si vous n'êtes pas satisfait de la méthode ci-dessus, vous pouvez écrire vos modules en utilisant le schéma d'injection de dépendance. Dans ce modèle, chaque module exporte une fonction d'usine (ou un constructeur de classe).

// horn.js
module.exports = function () {
    return {
        honk: function () {
            console.log("beep!");
        }
    };
};

// car.js
module.exports = function (horn) {
    return {
        honkHorn: function () {
            horn.honk();
        }
    };
};

// index.js
var horn = require("./horn")();
var car = require("./car")(horn);
car.honkHorn();

c'est très analogue à la méthode C# plus tôt en ce que le module index.js est responsable par exemple des cycles de vie et du câblage. Le test de l'unité est assez simple car vous pouvez simplement passer dans les mocks/stubs aux fonctions. Encore une fois, si cela est assez bon pour votre application aller avec.

Bolus DI Framework

contrairement à C#, il n'y a pas de cadres D'AI Standard établis pour aider à la gestion de votre dépendance. Il existe un certain nombre de cadres dans le registre de la NGP, mais aucun n'a été adopté à grande échelle. Bon nombre de ces options ont déjà été citées dans les autres réponses.

Je n'étais pas particulièrement heureux avec l'une des options disponibles, donc j'ai écrit mon propre appelé bolus . Bolus est conçu pour fonctionner avec du code écrit dans le style DI ci-dessus et tente d'être très sec et très simple. En utilisant les mêmes modules car.js et horn.js ci-dessus, vous pouvez réécrire le module index.js avec bolus comme:

// index.js
var Injector = require("bolus");
var injector = new Injector();
injector.registerPath("**/*.js");

var car = injector.resolve("car");
car.honkHorn();

L'idée de base est que vous créez un injecteur. Vous Enregistrez tous vos modules dans l'injecteur. Alors vous résolvez simplement ce dont vous avez besoin. Bolus va parcourir le graphe de dépendances et créer et injecter des dépendances au besoin. Vous n'enregistrez pas beaucoup dans un jouet exemple comme celui-ci, mais dans les grandes applications avec des arbres de dépendance compliqués les économies sont énormes.

bolus supporte un tas de fonctionnalités nifty comme les dépendances optionnelles et les globals de test, mais il y a deux avantages clés que j'ai vu par rapport au noeud standard.approche js. Tout d'abord, si vous avez beaucoup d'applications similaires, vous pouvez créer un privé mnp module pour votre base qui crée un injecteur et les registres des objets utiles. Alors vos applications spécifiques peuvent ajouter, remplacer, et de résoudre, au besoin, comme la façon dont AngularJS injecteur fonctionne. Deuxièmement, vous pouvez utiliser bolus pour gérer divers contextes de dépendances. Par exemple, vous pouvez utiliser middleware pour créer un injecteur enfant par demande, enregistrer le nom d'utilisateur, le nom de session, logger, etc. sur l'injecteur avec tous les modules en fonction de ceux-ci. Ensuite, résolvez ce dont vous avez besoin pour servir les requêtes. Cela vous donne des instances de vos modules par requête et évite d'avoir à passer l'enregistreur, etc. le long à chaque appel de fonction de module.

29
répondu Dave Johnson 2016-02-20 20:05:13

j'ai construit Electrolyte à cette fin. Les autres solutions d'injection de dépendances étaient trop invasives à mon goût, et jouer avec le require mondial est un grief particulier du mien.

Electrolyte englobe les modules, en particulier ceux qui exportent une fonction" setup " comme vous voyez dans Connect/Express middleware. Essentiellement, ces types de modules ne sont que des usines pour certains objets qu'ils renvoient.

par exemple, un module qui crée une connexion à une base de données:

var mysql = require('mysql');

exports = module.exports = function(settings) {
  var connection = mysql.createConnection({
    host: settings.dbHost,
    port: settings.dbPort
  });

  connection.connect(function(err) {
    if (err) { throw err; }
  });

  return connection;
}

exports['@singleton'] = true;
exports['@require'] = [ 'settings' ];

ce que vous voyez en bas sont annotations , un peu supplémentaire de métadonnées Qu'Electrolyte utilise pour instancier et injecter des dépendances, câblant automatiquement les composants de votre application ensemble.

pour créer une connexion de base de données:

var db = electrolyte.create('database');

électrolyte traverse de façon transitoire le @require " d dépendances, et l'injecte des instances comme arguments de la fonction exportée.

la clé est que c'est peu invasif. Ce module est entièrement utilisable, indépendamment de L'électrolyte lui-même. Cela signifie que vos tests unitaires peuvent tester juste le module en cours de test , en passant dans les objets simulés sans besoin de dépendances supplémentaires pour rebrancher les internes.

lors de l'exécution de l'application complète, L'électrolyte intervient à l'inter-module niveau, câblage des choses ensemble sans le besoin de globals, singletons ou plomberie excessive.

16
répondu Jared Hanson 2013-11-26 05:51:03

j'ai récemment vérifié ce thread pour la même raison que L'OP - most des libs que j'ai rencontrés réécrivent Temporairement l'instruction require. J'ai eu des degrés de succès avec cette méthode, et j'ai donc fini par utiliser l'approche suivante.

Dans le contexte d'une demande expresse - je envelopper app.js dans un fichier d'initialisation.fichier js:

var path = require('path');
var myapp = require('./app.js');

var loader = require('./server/services/loader.js');

// give the loader the root directory
// and an object mapping module names 
// to paths relative to that root
loader.init(path.normalize(__dirname), require('./server/config/loader.js')); 

myapp.start();

la carte d'objet passée au chargeur ressemble à ceci:

// live loader config
module.exports = {
    'dataBaseService': '/lib/dataBaseService.js'
}

// test loader config
module.exports = {
    'dataBaseService': '/mocks/dataBaseService.js'
    'otherService' : {other: 'service'} // takes objects too...
};

alors, plutôt que d'appeler directement require...

var myDatabaseService = loader.load('dataBaseService');

si aucun alias n'est localisé dans le chargeur - alors il sera par défaut à un require régulier. Ceci a deux avantages: je peux échanger dans n'importe quelle version de la classe, et il supprime la nécessité pour utiliser des noms de chemins relatifs tout au long de l'application (donc si j'ai besoin d'un lib personnalisé ci-dessous ou au-dessus du fichier courant, je n'ai pas besoin de parcourir, et require cache le module contre la même clé). Il me permet également de spécifier on se moque à tout moment dans l'application, plutôt que dans l'immédiat suite de tests.

je viens de publier un petit module npm pour la commodité:

https://npmjs.org/package/nodejs-simple-loader

5
répondu sunwukung 2013-08-07 10:23:40

j'ai regardé moi-même. Je n'aime pas introduire des bibliothèques de dépendances magic utils qui fournissent des mécanismes pour détourner mes importations de modules. Au lieu de cela, j'ai trouvé une "ligne directrice de conception" pour mon équipe afin d'indiquer assez explicitement quelles dépendances peuvent être moquées en introduisant une exportation de fonction d'usine dans mes modules.

je fais un usage extensif des fonctionnalités ES6 pour les paramètres et la déstructuration afin d'éviter certains boilerplate et fournir une dépendance nommée mécanisme de neutralisation.

voici un exemple:

import foo from './utils/foo';
import bob from './utils/bob';

// We export a factory which accepts our dependencies.
export const factory = (dependencies = {}) => {
  const {
    // The 'bob' dependency.  We default to the standard 'bob' imp if not provided.
    $bob = bob, 
    // Instead of exposing the whole 'foo' api, we only provide a mechanism
    // with which to override the specific part of foo we care about.
    $doSomething = foo.doSomething // defaults to standard imp if none provided.
  } = dependencies;  

  return function bar() {
    return $bob($doSomething());
  }
}

// The default implementation, which would end up using default deps.
export default factory();

Et voici un exemple de son utilisation

import { factory } from './bar';

const underTest = factory({ $bob: () => 'BOB!' }); // only override bob!
const result = underTest();

Excuse la syntaxe ES6 pour ceux qui ne la connaissent pas.

5
répondu ctrlplusb 2016-02-08 19:45:55

j'ai toujours aimé la simplicité du concept du CIO - "vous ne devez rien savoir sur l'environnement, vous serez appelé par quelqu'un quand il le faut "

mais toutes les implémentations du CIO que j'ai vues ont fait exactement le contraire - elles encombrent le code avec encore plus de choses que sans lui. Donc, j'ai créé mon propre CIO qui fonctionne comme je le voudrais - il reste caché et invisible 90% du temps .

il est utilisé dans MonoJS web framework http://monojs.org

je parle de choses simples, comme partager un objet de connexion de base de données, donc loin, mais je n'ai pas trouvé une solution qui me satisfasse.

c'est fait comme ceci - enregistrez le composant une fois dans la configuration.

app.register 'db', -> 
  require('mongodb').connect config.dbPath

et l'utiliser n'importe où

app.db.findSomething()

vous pouvez voir le code complet de définition de composant (avec connexion DB et D'Autres composants) ici https://github.com/sinizinairina/mono/blob/master/mono.coffee

C'est le seul endroit où vous devez dire au CIO quoi faire, après que tous ces composants seront créés et connectés automatiquement et vous n'aurez plus à voir le code spécifique du CIO dans votre application.

le CIO lui-même https://github.com/alexeypetrushin/miconjs

2
répondu Alexey Petrushin 2014-01-10 17:21:59

je pense que nous avons encore besoin de L'Injection de dépendance dans Nodejs parce qu'elle relâche les dépendances entre les services et rend l'application plus claire.

inspiré de Spring Framework , j'implémente aussi mon propre module pour supporter l'injection de dépendances dans Nodejs. Mon module est également capable de détecter les services code changes et auto reload sans redémarrer votre application.

visitez mon projet à: Buncha-CIO conteneur

Merci!

2
répondu ThoQ 2016-05-20 04:29:26

La réalité est que vous pouvez tester votre nœud.js sans conteneur CIO parce que JavaScript est un langage de programmation vraiment dynamique et vous pouvez modifier presque tout à l'exécution.

considérer ce qui suit:

import UserRepository from "./dal/user_repository";

class UserController {
    constructor() {
        this._repository = new UserRepository();
    }
    getUsers() {
        this._repository.getAll();
    }
}

export default UserController;

pour que vous puissiez remplacer le couplage entre les composants à l'exécution. J'aime à penser que nous devrions nous efforcer de découpler nos modules JavaScript.

la seule façon d'obtenir un découplage réel est par suppression de la référence au UserRepository :

class UserController {
    constructor(userRepository) {
        this._repository = userRepository;
    }
    getUsers() {
        this._repository.getAll();
    }
}

export default UserController;

cela signifie que vous devrez faire la composition objet ailleurs:

import UserRepository from "./dal/user_repository";
import UserController from "./dal/user_controller";

export default new UserController(new UserRepository());

j'aime l'idée de déléguer la composition d'objet à un conteneur IoC. Vous pouvez en savoir plus sur cette idée dans l'article l'état actuel de l'inversion de dépendance en JavaScript . L'article tente de démystifier certains "mythes JavaScript sur les conteneurs du CIO":

mythe 1: Il N'y a pas de place pour les conteneurs du CIO en JavaScript

Mythe 2: nous n'avons pas besoin de conteneurs IoC, nous avons déjà des chargeurs modules!

mythe 3: inversion de dépendance = = = dépendance par injection

si vous aimez aussi l'idée d'utiliser un conteneur IoC, vous pouvez jeter un oeil à InversifyJS. La dernière version (2.0.0) supporte de nombreux cas d'utilisation:

  • modules du noyau
  • Noyau middleware
  • Utiliser les classes, les littéraux de chaîne ou des Symboles comme la dépendance des identifiants
  • Injection de valeurs constantes
  • Injection de constructeurs de classe
  • l'Injection d'usines
  • usine Automobile
  • Injection de fournisseurs (async usine)
  • manipulateurs D'Activation (utilisés pour injecter des procurations)
  • multi injections
  • fixations étiquetées
  • balise Personnalisée décorateurs
  • Nommé liaisons
  • reliures contextuelles
  • Amicale des exceptions (par exemple, les dépendances Circulaires)

vous pouvez en savoir plus à ce sujet à InversifyJS .

2
répondu Remo H. Jansen 2016-06-23 13:19:27

pour ES6 j'ai développé ce conteneur https://github.com/zazoomauro/node-dependency-injection

import {ContainerBuilder} from 'node-dependency-injection'

let container = new ContainerBuilder()
container.register('mailer', 'Mailer')

ensuite, vous pouvez définir, par exemple, le choix du transport dans le conteneur:

import {ContainerBuilder} from 'node-dependency-injection'

let container = new ContainerBuilder()
container
  .register('mailer', 'Mailer')
  .addArgument('sendmail')

cette classe est maintenant beaucoup plus flexible que vous avez séparé le choix du transport hors de la mise en œuvre et dans le conteneur.

maintenant que le service de courrier est dans le conteneur vous pouvez l'injecter comme une dépendance d'autres classes. Si vous avez une classe de newsletter-Termanager comme celle-ci:

class NewsletterManager {
    construct (mailer, fs) {
        this._mailer = mailer
        this._fs = fs
    }
}

export default NewsletterManager

lors de la définition du service newsletter ter_manager, le service mailer n'existe pas encore. Utilisez la classe de référence pour dire au conteneur d'injecter le service mailer quand il initialise le gestionnaire de newsletter:

import {ContainerBuilder, Reference, PackageReference} from 'node-dependency-injection'
import Mailer from './Mailer'
import NewsletterManager from './NewsletterManager'

let container = new ContainerBuilder()

container
  .register('mailer', Mailer)
  .addArgument('sendmail')

container
  .register('newsletter_manager', NewsletterManager)
  .addArgument(new Reference('mailer'))
  .addArgument(new PackageReference('fs-extra'))

vous pouvez également configurer le conteneur avec des fichiers de configuration comme les fichiers Yaml, Json ou JS

le conteneur de service peut être compilé pour diverses raisons. Ces raisons comprennent la vérification de tout problème potentiel, comme les renvois circulaires, et le fait de rendre le contenant plus efficace.

container.compile()
2
répondu Mauro 2017-01-27 09:23:26

Cela dépend de la conception de votre application. Vous pouvez évidemment faire une injection java like où vous créez un objet d'une classe avec la dépendance passée dans le constructeur comme ceci.

function Cache(store) {
   this._store = store;
}

var cache = new Cache(mysqlStore);

si vous ne faites pas de OOP en javascript, vous pouvez créer une fonction init qui met tout en place.

cependant, il y a une autre approche que vous pouvez prendre qui est plus fréquente dans un système basé sur des événements tels que le noeud.js. Si vous pouvez vous modeler application pour(la plupart du temps) de la loi sur les événements puis tout ce que vous devez faire est de mettre tout en place(qui j'ai l'habitude de le faire en appelant une fonction init) et émettent des événements à partir d'une souche. Cela rend les tests plus faciles et lisibles.

1
répondu Satyam Shekhar 2012-02-12 19:19:49

jetez un coup d'oeil à dips (un système simple mais puissant d'injection de dépendances et de gestion des entités (fichiers) pour le noeud.js)

https://github.com/devcrust/node-dips

1
répondu Mario 2014-01-23 09:54:02

Google di.js travaille sur nodejs (+ navigateur) (+ ES6)

1
répondu Amit Portnoy 2015-06-14 13:47:00

j'ai récemment créé une bibliothèque appelée circuitbox qui vous permet d'utiliser dépendance-injection avec noeud.js. Il fait une véritable injection de dépendances par rapport à la plupart des bibliothèques basées sur la recherche de dépendances que j'ai vues. Circuitbox supporte également les routines de création et d'initialisation asynchrones. Voici un exemple:

suppose que le code suivant est dans un fichier appelé consoleMessagePrinter.js

'use strict';

// Our console message printer
// deps is injected by circuitbox with the dependencies
function ConsoleMessagePrinter(deps) {
  return {
    print: function () {
      console.log(deps.messageSource.message());
    }
  };
}

module.exports = ConsoleMessagePrinter;

supposons que la suite est dans le fichier principal.js

'use strict';

// our simple message source
// deps is injected by circuitbox with the dependencies
var simpleMessageSource = function (deps) {
  return {
    message: function () {
      return deps.message;
    }
  };
};

// require circuitbox
var circuitbox = require('../lib');

// create a circuitbox
circuitbox.create({
  modules: [
    function (registry) {
      // the message to be used
      registry.for('message').use('This is the message');

      // define the message source
      registry.for('messageSource').use(simpleMessageSource)
        .dependsOn('message');

      // define the message printer - does a module.require internally
      registry.for('messagePrinter').requires('./consoleMessagePrinter')
        .dependsOn('messageSource');
    }
  ]
}).done(function (cbx) {

  // get the message printer and print a message
  cbx.get('messagePrinter').done(function (printer) {
    printer.print();
  }, function (err) {
    console.log('Could not recieve a printer');
    return;
  });

}, function (err) {
  console.log('Could not create circuitbox');
});

Circuitbox vous permet de définir vos composants et de déclarer leurs dépendances en tant que modules. Une fois initialisé, il vous permet de récupérer un composant. Circuitbox injecte automatiquement tous les composants dont le composant cible a besoin et vous les donne à utiliser.

le projet est en version alpha. Vos commentaires, idées et commentaires sont les bienvenus.

Espère que cela aide!

0
répondu oddjobsman 2013-12-31 05:56:40

je pense que les autres postes ont fait un excellent travail dans l'argument pour l'utilisation de DI. Pour moi, les raisons sont

  1. injecter des dépendances sans connaître leurs chemins. Cela signifie que si vous changez l'emplacement d'un module sur un disque ou l'échangez avec un autre, vous n'avez pas besoin de toucher tous les fichiers qui en dépendent.

  2. il est beaucoup plus facile de simuler des dépendances pour le test sans la douleur d'Outrepasser le mondial require la fonction d'une manière qui fonctionne sans problèmes.

  3. il vous aide à organiser et raisonner au sujet de votre application que les modules librement couplés.

mais j'ai eu beaucoup de mal à trouver un cadre DI que mon équipe et moi pouvons facilement adopter. Donc j'ai récemment construit un cadre appelé deppie basé sur ces caractéristiques

  • API minimale qui peut être appris en quelques minutes
  • Pas de code supplémentaire/config/annotations nécessaires
  • un pour Un mappage direct require modules
  • peut être adopté en partie pour fonctionner avec le code existant
0
répondu Gaafar 2016-06-18 00:02:40

il doit être souple et simple comme ceci:

var MyClass1 = function () {}
var MyClass2 = function (myService1) {
    // myService1.should.be.instanceof(MyClass1); 
}


container.register('myService1', MyClass1);
container.register('myService2', MyClass2, ['myService1']);

j'ai écrit un article sur L'Injection de dépendance dans le noeud.js.

j'espère que cela pourra vous aider.

0
répondu slava 2016-06-23 18:29:32

Node.js nécessite DI autant que n'importe quelle autre plate-forme. Si vous construisez quelque chose de gros, DI vous facilitera la tâche de vous moquer des dépendances de votre code et de le tester à fond.

vos modules de couche de base de données par exemple, ne devraient pas seulement être requis à vos modules de code d'affaires parce que, lorsque l'unité teste ces modules de code d'affaires, les ofa se chargeront et se connecteront à la base de données.

Une solution serait de passer les dépendances comme paramètres du module:

module.exports = function (dep1, dep2) {
// private methods

   return {
    // public methods
       test: function(){...}
   }
}

de cette façon, les dépendances peuvent être moquées facilement et naturellement et vous pouvez rester concentré sur l'essai de votre code, sans utiliser de bibliothèque tierce partie délicate.

il y a d'autres solutions (broadway, architect etc) qui peuvent vous aider avec cela. bien qu'ils peuvent faire plus que ce que vous voulez ou utiliser le désordre.

0
répondu user2468170 2016-10-21 09:19:21

j'ai développé une bibliothèque qui gère l'injection de dépendances d'une manière simple, ce qui diminue le code boilerplate. Chaque module est défini par un nom unique et une fonction de contrôleur. Les paramètres du contrôleur reflètent les dépendances du module.

plus d'informations sur KlarkJS

bref exemple:

KlarkModule(module, 'myModuleName1', function($nodeModule1, myModuleName2) {
    return {
        log: function() { console.log('Hello from module myModuleName1') }
    };
});
  • myModuleName1 est le nom du module.
  • $nodeModule1 est une bibliothèque externe de node_module . Le nom se résout à node-module1 . Le préfixe $ indique qu'il s'agit d'un module externe.
  • myModuleName2 est le nom d'un module interne.
  • La valeur de retour du contrôleur est utilisé à partir d'autres modules internes, lorsqu'ils définissent le paramètre myModuleName1 .
0
répondu Apostolidis 2016-12-28 11:43:47

j'ai découvert cette question pendant que répondant à un problème sur mon propre module DI demandant pourquoi on aurait jamais besoin d'un système DI pour la programmation de NodeJS.

la réponse tend clairement à celles données dans ce fil: cela dépend. Il y a des compromis pour les deux approches et la lecture des réponses à cette question en donne une bonne forme.

Donc, la vraie réponse à cette question devrait être que, dans certaines situations, vous utiliserait un système D'ai, dans d'autres pas.

cela dit, ce que vous voulez en tant que développeur est de ne pas vous répéter et de réutiliser vos services à travers vos diverses applications.

cela signifie que nous devrions écrire des services qui sont prêts à être utilisés dans le système DI mais qui ne sont pas liés aux bibliothèques DI. Pour moi, cela signifie que nous devrions écrire des services comme ceci:

module.exports = initDBService;

// Tells any DI lib what it expects to find in it context object
// The $inject prop is the de facto standard for DI imo 
initDBService.$inject = ['ENV'];

// Note the context object, imo, a DI tool should bring
// services in a single context object
function initDBService({ ENV }) {
/// actual service code
}

de cette façon votre service fonctionne peu importe si vous l'utilisez avec ou sans DI tool.

0
répondu nfroidure 2017-05-20 10:24:01

j'ai travaillé avec .Net, PHP et Java pendant longtemps donc je voulais avoir une Injection de dépendance pratique dans NodeJS aussi. Les gens ont dit que le DI intégré dans NodeJS est suffisant car nous pouvons l'obtenir avec Module. Mais ça ne m'a pas bien satisfait. Je voulais garder un Module pas plus qu'un cours. De plus, je voulais que le DI ait un support complet pour la gestion du cycle de vie des modules (module singleton, module transitoire, etc.) mais avec le module Node, j'ai dû écrire du code manuel très souvent. Enfin, je voulais faciliter le test de L'Unité. C'est pourquoi j'ai créé une Injection de dépendance pour moi-même.

si vous cherchez un AI, essayez-le. Il peut être trouvé ici: https://github.com/robo-creative/nodejs-robo-container . Il est entièrement documenté. Il aborde également certains problèmes communs avec DI et la façon de les résoudre en OOP. Espérons que cela aide.

0
répondu Robo 2017-07-11 07:25:08