He estado trabajando con nodejs últimamente y todavía me estoy familiarizando con el sistema de módulos, así que me disculpo si esta es una pregunta obvia. Quiero un código similar al siguiente a continuación:
a.js (el archivo principal se ejecuta con el nodo)
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;
Mi problema parece ser que no puedo acceder a la instancia de ClassA desde una instancia de ClassB.
¿Existe una forma correcta / mejor de estructurar módulos para lograr lo que quiero? ¿Hay una mejor manera de compartir variables entre módulos?
Respuestas:
Si bien node.js sí permite
require
dependencias circulares , como ha descubierto, puede ser bastante complicado y probablemente sea mejor reestructurar su código para no necesitarlo. Tal vez cree una tercera clase que use las otras dos para lograr lo que necesita.fuente
exports = {}
en la parte superior de su código y luegoexports = yourData
al final de su código. Con esta práctica evitará casi todos los errores de dependencias circulares.Intente establecer propiedades en
module.exports
lugar de reemplazarlo por completo. Por ejemplo,module.exports.instance = new ClassA()
ena.js
,module.exports.ClassB = ClassB
enb.js
. Cuando realiza dependencias de módulos circulares, el módulo requerido obtendrá una referencia a un incompletomodule.exports
del módulo requerido, al que puede agregar otras propiedades más adelante, pero cuando configura todomodule.exports
, realmente crea un nuevo objeto que el módulo requerido no tiene manera de acceder.fuente
module.exports
sin reemplazarlo por completo, para permitir que otras clases 'construyan' una instancia de la clase?[EDITAR] no es 2015 y la mayoría de las bibliotecas (es decir, express) han realizado actualizaciones con mejores patrones, por lo que las dependencias circulares ya no son necesarias. Recomiendo simplemente no usarlos .
Sé que estoy desenterrando una respuesta anterior aquí ... El problema aquí es que module.exports se define después de que necesita ClassB. (que muestra el enlace de JohnnyHK) Las dependencias circulares funcionan muy bien en Node, solo se definen sincrónicamente. Cuando se usan correctamente, en realidad resuelven muchos problemas de nodos comunes (como acceder a express.js
app
desde otros archivos)Solo asegúrese de que sus exportaciones necesarias estén definidas antes de requerir un archivo con una dependencia circular.
Esto se romperá:
Esto funcionará:
Uso este patrón todo el tiempo para acceder a express.js
app
en otros archivos:fuente
app = express()
A veces es realmente artificial introducir una tercera clase (como aconseja JohnnyHK), así que además de Ianzz: si desea reemplazar el module.exports, por ejemplo, si está creando una clase (como el archivo b.js en el ejemplo anterior), esto también es posible, solo asegúrese de que en el archivo que está comenzando la circular requiera, la declaración 'module.exports = ...' ocurre antes de la declaración require.
a.js (el archivo principal se ejecuta con el nodo)
b.js
fuente
La solución es 'declarar adelante' su objeto de exportación antes de requerir cualquier otro controlador. Entonces, si estructura todos sus módulos de esta manera y no se encontrará con ningún problema como ese:
fuente
exports.foo = function() {...}
lugar. Definitivamente hizo el truco. ¡Gracias!module.exports
ya es un objeto simple por defecto, por lo que su línea de "declaración directa" es redundante.Se extiende una solución que requiere un cambio mínimo en
module.exports
lugar de anularla.a.js: punto de entrada de la aplicación y módulo que usa el método do de b.js *
b.js: módulo que utiliza el método do de a.js
Funcionará y producirá:
Si bien este código no funcionará:
a.js
b.js
Salida:
fuente
underscore
, entonces los ES6Object.assign()
pueden hacer el mismo trabajo que_.extend()
está haciendo en esta respuesta.¿Qué pasa con la pereza que requiere solo cuando lo necesita? Entonces su b.js se ve de la siguiente manera
Por supuesto, es una buena práctica poner todas las declaraciones obligatorias en la parte superior del archivo. Pero no son las ocasiones, cuando me perdono para recoger algo fuera de un módulo de otro modo no relacionado. Llámalo hack, pero a veces es mejor que introducir una dependencia adicional, o agregar un módulo adicional o agregar nuevas estructuras (EventEmitter, etc.)
fuente
Otro método que he visto hacer es exportar en la primera línea y guardarlo como una variable local como esta:
Tiendo a usar este método, ¿conoces alguna desventaja?
fuente
module.exports.func1 =
,module.exports.func2 =
Puede resolver esto fácilmente: simplemente exporte sus datos antes de requerir cualquier otra cosa en los módulos donde usa module.exports:
classA.js
classB.js
fuente
Similar a las respuestas de lanzz y setect, he estado usando el siguiente patrón:
Las
Object.assign()
copias de los miembros en elexports
objeto que ya se ha dado a otros módulos.La
=
asignación es lógicamente redundante, ya que solo se está configurandomodule.exports
a sí misma, pero la estoy usando porque ayuda a mi IDE (WebStorm) a reconocer quefirstMember
es una propiedad de este módulo, por lo que "Ir a -> Declaración" (Cmd-B) y otras herramientas funcionarán desde otros archivos.Este patrón no es muy bonito, por lo que solo lo uso cuando es necesario resolver un problema de dependencia cíclica.
fuente
Aquí hay una solución rápida que he encontrado uso completo.
En el archivo 'a.js'
En el archivo 'b.js' escriba lo siguiente
De esta manera, en la próxima iteración del evento, las clases de bucle se definirán correctamente y esas declaraciones obligatorias funcionarán como se esperaba.
fuente
En realidad terminé requiriendo mi dependencia con
No es bonita, pero funciona. Es más comprensible y honesto que cambiar b.js (por ejemplo, solo aumentar modules.export), que de lo contrario es perfecto como está.
fuente
Una forma de evitarlo es no requerir un archivo en otro, simplemente pasarlo como argumento a una función, lo que sea que necesite en otro archivo. De esta manera, nunca surgirá una dependencia circular.
fuente