Eu tenho trabalhado com o nodejs ultimamente e ainda estou familiarizado com o sistema de módulos, então peço desculpas se esta for uma pergunta óbvia. Quero código aproximadamente como o seguinte abaixo:
a.js (o arquivo principal executado com o nó)
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;
Meu problema parece ser que não consigo acessar a instância da ClassA de dentro de uma instância da ClassB.
Existe uma maneira correta / melhor de estruturar os módulos para alcançar o que eu quero? Existe uma maneira melhor de compartilhar variáveis entre módulos?
Respostas:
Embora o node.js permita
require
dependências circulares , como você descobriu, pode ser bastante complicado e provavelmente é melhor reestruturar seu código para não precisar dele. Talvez crie uma terceira classe que use as outras duas para realizar o que você precisa.fonte
exports = {}
na parte superior do seu código e depoisexports = yourData
no final do seu código. Com esta prática, você evitará quase todos os erros das dependências circulares.Tente ativar as propriedades
module.exports
, em vez de substituí-las completamente. Por exemplo,module.exports.instance = new ClassA()
dentroa.js
,module.exports.ClassB = ClassB
dentrob.js
. Quando você cria dependências de módulos circulares, o módulo exigente obtém uma referência incompletamodule.exports
do módulo necessário, no qual você pode adicionar outras propriedades posteriormente, mas quando define o conjuntomodule.exports
, na verdade, cria um novo objeto que o módulo exigente não possui. maneira de acessar.fonte
module.exports
sem substituí-lo completamente, para permitir que outras classes 'construíssem' uma instância da classe?[EDIT] não é 2015 e a maioria das bibliotecas (ou seja, express) fez atualizações com melhores padrões, de modo que as dependências circulares não são mais necessárias. Eu recomendo simplesmente não usá-los .
Eu sei que estou desenterrando uma resposta antiga aqui ... O problema aqui é que module.exports é definido depois que você precisa da ClassB. (que o link de JohnnyHK mostra) As dependências circulares funcionam muito bem no Node, apenas são definidas de forma síncrona. Quando usados corretamente, eles realmente resolvem muitos problemas comuns de nó (como acessar o express.js
app
de outros arquivos)Apenas verifique se as exportações necessárias estão definidas antes de você precisar de um arquivo com uma dependência circular.
Isso vai quebrar:
Isso funcionará:
Eu uso esse padrão o tempo todo para acessar o express.js
app
em outros arquivos:fonte
app = express()
Às vezes, é realmente artificial introduzir uma terceira classe (como JohnnyHK aconselha), portanto, além de Ianzz: Se você deseja substituir o module.exports, por exemplo, se você estiver criando uma classe (como o arquivo b.js em no exemplo acima), isso também é possível, apenas certifique-se de que, no arquivo que está iniciando a requisição circular, a instrução 'module.exports = ...' ocorra antes da declaração de exigência.
a.js (o arquivo principal executado com o nó)
b.js
fonte
A solução é 'declarar adiante' seu objeto de exportação antes de exigir qualquer outro controlador. Portanto, se você estruturar todos os seus módulos como este e não terá problemas assim:
fonte
exports.foo = function() {...}
. Definitivamente fez o truque. Obrigado!module.exports
já é um objeto simples, por padrão, portanto, sua linha de "declaração direta" é redundante.Uma solução que requer alterações mínimas está se estendendo em
module.exports
vez de substituí-la.a.js - ponto de entrada do aplicativo e módulo que usam o método do b.js *
b.js - módulo que usa o método do a.js
Funcionará e produzirá:
Embora este código não funcione:
a.js
b.js
Resultado:
fonte
underscore
, os ES6Object.assign()
podem fazer o mesmo trabalho que_.extend()
está fazendo nesta resposta.E quanto à preguiça de exigir apenas quando você precisar? Portanto, seu b.js tem a seguinte aparência
Obviamente, é uma boa prática colocar todas as instruções de exigência no topo do arquivo. Mas não são ocasiões, onde eu me perdoar por escolher algo fora de um módulo de outro modo não relacionado. Chame isso de hack, mas às vezes isso é melhor do que introduzir uma dependência adicional ou adicionar um módulo extra ou adicionar novas estruturas (EventEmitter, etc)
fonte
Um outro método que eu vi as pessoas fazer é exportar na primeira linha e salvá-lo como uma variável local como esta:
Eu costumo usar esse método, você conhece alguma desvantagem dele?
fonte
module.exports.func1 =
,module.exports.func2 =
Você pode resolver isso facilmente: basta exportar seus dados antes de precisar de mais alguma coisa nos módulos em que você usa module.exports:
classA.js
classB.js
fonte
Semelhante às respostas de lanzz e setect, tenho usado o seguinte padrão:
As
Object.assign()
cópias são copiadas para oexports
objeto que já foi fornecido para outros módulos.A
=
atribuição é logicamente redundante, pois está apenas se configurandomodule.exports
, mas eu a estou usando porque ajuda meu IDE (WebStorm) a reconhecer quefirstMember
é uma propriedade deste módulo, então "Vá para -> Declaração" (Cmd-B) e outras ferramentas funcionarão com outros arquivos.Esse padrão não é muito bonito; portanto, eu o uso apenas quando um problema de dependência cíclica precisa ser resolvido.
fonte
Aqui está uma solução rápida que eu achei totalmente útil.
No arquivo 'a.js'
No arquivo 'b.js', escreva o seguinte
Dessa maneira, na próxima iteração das classes do loop de eventos, será definido corretamente e as instruções de solicitação funcionarão conforme o esperado.
fonte
Na verdade, acabei exigindo minha dependência de
Não é bonito, mas funciona. É mais compreensível e honesto do que alterar o b.js (por exemplo, apenas aumentando o modules.export), que de outra forma é perfeito como está.
fonte
Uma maneira de evitá-lo é não exigir um arquivo em outro, apenas passá-lo como argumento para uma função do que você precisar em outro arquivo. Dessa maneira, a dependência circular nunca surgirá.
fonte