219 votes

Comment gérer les dépendances cycliques dans Node.js ?

J'ai travaillé avec nodejs Ces derniers temps, je suis encore en train de me familiariser avec la module Je vous prie donc de m'excuser si cette question est évidente. J'ai besoin d'un code qui ressemble à peu près à ce qui suit :

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 une manière correcte / meilleure de structurer modules pour obtenir ce que je veux ? Existe-t-il une meilleure façon de partager variables à travers modules ?

6voto

Bence Gedai Points 686

Une autre méthode que j'ai vue consiste à exporter à la première ligne et à l'enregistrer en tant que variable locale, comme ceci :

let self = module.exports = {};

const a = require('./a');

// Exporting the necessary functions
self.func = function() { ... }

J'ai tendance à utiliser cette méthode, connaissez-vous des inconvénients ?

5voto

Camilo Points 98

TL;DR

Il suffit d'utiliser exports.someMember = someMember au lieu de module.exports = { // new object } .

Réponse élargie

Après avoir lu la réponse de lanzz, j'ai enfin pu comprendre ce qui se passe ici, et je vais donc donner mon avis sur le sujet, en prolongeant sa réponse.

Voyons cet exemple :

a.js

console.log("a starting");

console.log("a requires b");
const b = require("./b");
console.log("a gets b =", b);

function functionA() {
  console.log("function a");
}

console.log("a done");
exports.functionA = functionA;

b.js

console.log("b starting");

console.log("b requires a");
const a = require("./a");
console.log("b gets a =", a);

function functionB() {
  console.log("On b, a =", a)
}

console.log("b done");
exports.functionB = functionB;

main.js

const a = require("./a");
const b = require("./b");

b.functionB()

Sortie

a starting
a requires b
b starting
b requires a
b gets a = {}
b done
a gets b = { functionB: [Function: functionB] }
a done
On b, a = { functionA: [Function: functionA] }

Nous voyons ici que dans un premier temps b reçoit un objet vide en tant que a et ensuite une fois a est entièrement chargé, cette référence est mise à jour par l'intermédiaire de exports.functionA = functionA . Si vous remplacez le module entier par un autre objet, par l'intermédiaire de module.exports alors b perdra la référence de a car il pointera vers le même objet vide depuis le début, au lieu de pointer vers le nouvel objet.

Ainsi, si vous exportez a comme ceci : module.exports = { functionA: functionA } , alors la sortie sera :

a starting
a requires b
b starting
b requires a
b gets a = {}
b done
a gets b = { functionB: [Function: functionB] }
a done
On b, a = {} // same empty object

4voto

zevero Points 29

En fait, j'ai fini par exiger ma dépendance avec

 var a = null;
 process.nextTick(()=>a=require("./a")); //Circular reference!

Ce n'est pas très joli, mais ça marche. C'est plus compréhensible et plus honnête que de modifier b.js (par exemple en augmentant seulement modules.export), qui par ailleurs est parfait tel quel.

3voto

Voici une solution rapide que j'ai trouvée et que j'utilise pleinement.

Sur le fichier 'a.js'

let B;
class A{
  constructor(){
    process.nextTick(()=>{
      B = require('./b')
    })
  } 
}
module.exports = new A();

Dans le fichier "b.js", écrivez ce qui suit

let A;
class B{
  constructor(){
    process.nextTick(()=>{
      A = require('./a')
    })
  } 
}
module.exports = new B();

Ainsi, lors de la prochaine itération de la boucle d'événements, les classes seront définies correctement et les instructions "require" fonctionneront comme prévu.

0voto

sagar saini Points 97

Une façon de l'éviter est de ne pas exiger un fichier dans un autre, mais de le passer comme argument à une fonction, quel que soit le fichier dont on a besoin. De cette manière, il n'y aura jamais de dépendance circulaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X