J'ai travaillé avec nodejs ces derniers temps et je me suis toujours familiarisé avec le système de modules, alors excuses si c'est une question évidente. Je veux du code à peu près comme ci-dessous:
a.js (le fichier principal exécuté avec node)
var ClassB = require("./b");
var ClassA = function() {
this.thing = new ClassB();
this.property = 5;
}
var a = new ClassA();
module.exports = a;
b.js
var a = require("./a");
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
Mon problème semble être que je ne peux pas accéder à l'instance de ClassA à partir d'une instance de ClassB.
Existe-t-il un moyen correct / meilleur de structurer les modules pour obtenir ce que je veux? Existe-t-il une meilleure façon de partager des variables entre les modules?
Réponses:
Bien que node.js autorise les
require
dépendances circulaires , comme vous l'avez trouvé, cela peut être assez compliqué et il vaut probablement mieux restructurer votre code pour ne pas en avoir besoin. Créez peut-être une troisième classe qui utilise les deux autres pour accomplir ce dont vous avez besoin.la source
exports = {}
en haut de votre code, puisexports = yourData
à la fin de votre code. Avec cette pratique, vous éviterez presque toutes les erreurs des dépendances circulaires.Essayez de définir les propriétés au
module.exports
lieu de les remplacer complètement. Par exemple,module.exports.instance = new ClassA()
dansa.js
,module.exports.ClassB = ClassB
dansb.js
. Lorsque vous créez des dépendances de modules circulaires, le module requérant obtiendra une référence à unmodule.exports
module incomplet du module requis, sur lequel vous pouvez ajouter d'autres propriétés ultérieurement, mais lorsque vous définissez l'ensemblemodule.exports
, vous créez en fait un nouvel objet sur lequel le module requérant n'a pas moyen d'accès.la source
module.exports
sans le remplacer complètement, pour permettre à d'autres classes de «construire» une instance de la classe?[EDIT] ce n'est pas 2015 et la plupart des bibliothèques (c'est-à-dire express) ont fait des mises à jour avec de meilleurs modèles donc les dépendances circulaires ne sont plus nécessaires. Je recommande simplement de ne pas les utiliser .
Je sais que je déterre une vieille réponse ici ... Le problème ici est que module.exports est défini après que vous ayez besoin de ClassB. (ce que montre le lien de JohnnyHK) Les dépendances circulaires fonctionnent très bien dans Node, elles sont simplement définies de manière synchrone. Lorsqu'ils sont utilisés correctement, ils résolvent en fait de nombreux problèmes de nœuds courants (comme accéder à express.js à
app
partir d'autres fichiers)Assurez-vous simplement que vos exportations nécessaires sont définies avant de demander un fichier avec une dépendance circulaire.
Cela va casser:
Cela fonctionnera:
J'utilise ce modèle tout le temps pour accéder à express.js
app
dans d'autres fichiers:la source
app = express()
Parfois, il est vraiment artificiel d'introduire une troisième classe (comme le conseille JohnnyHK), donc en plus de Ianzz: Si vous voulez remplacer le module.exports, par exemple si vous créez une classe (comme le fichier b.js dans l'exemple ci-dessus), cela est également possible, assurez-vous simplement que dans le fichier qui démarre la circulaire require, l'instruction 'module.exports = ...' arrive avant l'instruction require.
a.js (le fichier principal exécuté avec node)
b.js
la source
La solution est de «déclarer en avant» votre objet d'exportations avant de requérir un autre contrôleur. Donc, si vous structurez tous vos modules comme ceci et que vous ne rencontrerez aucun problème de ce genre:
la source
exports.foo = function() {...}
place. Vraiment fait l'affaire. Merci!module.exports
est déjà un objet simple par défaut, donc votre ligne "déclaration avant" est redondante.Une solution qui nécessite un changement minimal consiste à étendre
module.exports
au lieu de la remplacer.a.js - point d'entrée d'application et module utilisant la méthode do from b.js *
b.js - module qui utilise la méthode do à partir de a.js
Il fonctionnera et produira:
Bien que ce code ne fonctionnera pas:
a.js
b.js
Production:
la source
underscore
, alors ES6Object.assign()
peut faire le même travail que_.extend()
dans cette réponse.Qu'en est-il de la paresse exigeant uniquement lorsque vous en avez besoin? Donc votre b.js ressemble à ceci
Bien sûr, il est recommandé de placer toutes les instructions require au-dessus du fichier. Mais il y a des occasions où je me pardonne d'avoir choisi quelque chose dans un module autrement sans rapport. Appelez cela un hack, mais parfois c'est mieux que d'introduire une dépendance supplémentaire, ou d'ajouter un module supplémentaire ou d'ajouter de nouvelles structures (EventEmitter, etc.)
la source
Une autre méthode que j'ai vue des gens est d'exporter à la première ligne et de l'enregistrer en tant que variable locale comme celle-ci:
J'ai tendance à utiliser cette méthode, connaissez-vous ses inconvénients?
la source
module.exports.func1 =
,module.exports.func2 =
Vous pouvez résoudre ce problème facilement: exportez simplement vos données avant de demander quoi que ce soit d'autre dans les modules où vous utilisez module.exports:
classA.js
classB.js
la source
Semblable aux réponses de lanzz et setect, j'ai utilisé le modèle suivant:
Les
Object.assign()
copies des membres dans l'exports
objet qui a déjà été donné à d' autres modules.L'
=
affectation est logiquement redondante, car elle se définit simplementmodule.exports
, mais je l'utilise car elle aide mon IDE (WebStorm) à reconnaître quefirstMember
c'est une propriété de ce module, donc "Aller à -> Déclaration" (Cmd-B) et d'autres outils fonctionneront à partir d'autres fichiers.Ce modèle n'est pas très joli, donc je ne l'utilise que lorsqu'un problème de dépendance cyclique doit être résolu.
la source
Voici une solution de contournement rapide que j'ai trouvée pleinement utilisée.
Dans le fichier 'a.js'
Sur le fichier 'b.js', écrivez ce qui suit
De cette façon, lors de la prochaine itération, les classes de la boucle d'événements seront définies correctement et les instructions require fonctionneront comme prévu.
la source
En fait, j'ai fini par exiger ma dépendance avec
Ce n'est pas beau, mais ça marche. C'est plus compréhensible et honnête que de changer b.js (par exemple en augmentant uniquement les modules.export), qui autrement est parfait tel quel.
la source
Une façon de l'éviter est de ne pas avoir besoin d'un fichier dans un autre, simplement de le transmettre comme argument à une fonction, ce dont vous avez besoin dans un autre fichier. De cette manière, la dépendance circulaire ne se produira jamais.
la source