Jak radzić sobie z cyklicznymi zależnościami w węźle.js
Ostatnio pracowałem z nodejsem i wciąż zajmuję się systemem modułów, więc przepraszam, jeśli jest to oczywiste pytanie. Chcę kod mniej więcej taki jak poniżej:
A. js (główny plik uruchamiany z węzłem)
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;
Mój problem polega na tym, że nie mogę uzyskać dostępu do instancji ClassA z poziomu instancji ClassB.
Czy istnieje poprawny / lepszy sposób na strukturę modułów, aby osiągnąć to, czego chcę? Czy istnieje lepszy sposób dzielenia zmiennych między modułami?
12 answers
While node.js pozwala na okrągłe require
zależności, jak się okazało może to być dość brudny i prawdopodobnie lepiej będzie, jeśli zmienisz swój kod, aby go nie potrzebował. Może stwórz trzecią klasę, która użyje pozostałych dwóch, aby osiągnąć to, czego potrzebujesz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-22 01:16:45
Spróbuj ustawić właściwości na module.exports
, zamiast całkowicie je zastępować. Np. module.exports.instance = new ClassA()
w a.js
, module.exports.ClassB = ClassB
w b.js
. Kiedy tworzysz okrągłe zależności modułu, Moduł wymagający otrzyma odniesienie do niekompletnego module.exports
z wymaganego modułu, do którego możesz dodać inne właściwości, ale gdy ustawisz cały module.exports
, w rzeczywistości tworzysz nowy obiekt, do którego moduł wymagający nie ma dostępu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-03 18:54:03
[edytuj] nie jest 2015 i większość bibliotek (np. express) wprowadziła aktualizacje z lepszymi wzorcami, więc kołowe zależności nie są już potrzebne. Polecam po prostu nie używać ich .
Wiem, że szukam starej odpowiedzi... Problemem jest ten moduł.eksport jest zdefiniowany po wymagasz ClassB. (co pokazuje link JohnnyHK) Okrężne zależności działają świetnie w węzłach, są po prostu definiowane synchronicznie. Gdy są właściwie używane, faktycznie rozwiązują wiele typowych problemów z węzłami (np. dostęp do express.js
app
z innych plików)
Po prostu upewnij się, że eksport jest zdefiniowany przed potrzebujesz pliku z zależnością Okrężną.
To się zepsuje:
var ClassA = function(){};
var ClassB = require('classB'); //will require ClassA, which has no exports yet
module.exports = ClassA;
To zadziała:
var ClassA = module.exports = function(){};
var ClassB = require('classB');
Używam tego wzoru cały czas, aby uzyskać dostęp do expressa.js app
w innych plikach:
var express = require('express');
var app = module.exports = express();
// load in other dependencies, which can now require this file and use app
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-04 16:00:22
Czasami jest naprawdę sztucznie wprowadzić trzecią klasę( jak radzi JohnnyHK), więc oprócz Ianzz: Jeśli chcesz wymienić moduł.eksportuje, na przykład, jeśli tworzysz klasę (jak plik b. js w powyższym przykładzie), jest to również możliwe, po prostu upewnij się, że w pliku, który się uruchamia circular require, 'moduł.exports = ...'oświadczenie dzieje się przed oświadczeniem require.
A. js (plik główny uruchamia się z 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 ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
var a = require("./a"); // <------ this is the only necessary change
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-31 06:26:17
Rozwiązaniem jest "przekazanie deklaracji" eksportowanego obiektu przed wymaganiem jakiegokolwiek innego kontrolera. Więc jeśli uporządkujesz wszystkie swoje moduły w ten sposób i nie napotkasz żadnych problemów takich jak ten:
// Module exports forward declaration:
module.exports = {
};
// Controllers:
var other_module = require('./other_module');
// Functions:
var foo = function () {
};
// Module exports injects:
module.exports.foo = foo;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-18 00:35:39
Rozwiązaniem wymagającym minimalnej zmiany jest rozszerzenie module.exports
zamiast nadpisanie go.
A. js-app entry point and module which use method do from b. js *
_ = require('underscore'); //underscore provides extend() for shallow extend
b = require('./b'); //module `a` uses module `b`
_.extend(module.exports, {
do: function () {
console.log('doing a');
}
});
b.do();//call `b.do()` which in turn will circularly call `a.do()`
B. js-moduł wykorzystujący metodę do from a. js
_ = require('underscore');
a = require('./a');
_.extend(module.exports, {
do: function(){
console.log('doing b');
a.do();//Call `b.do()` from `a.do()` when `a` just initalized
}
})
Będzie działać i produkować:
doing b
doing a
Podczas gdy ten kod nie będzie działał:
A. js
b = require('./b');
module.exports = {
do: function () {
console.log('doing a');
}
};
b.do();
B. js
a = require('./a');
module.exports = {
do: function () {
console.log('doing b');
}
};
a.do();
Wyjście:
node a.js
b.js:7
a.do();
^
TypeError: a.do is not a function
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-12 21:19:24
A co z leniwym wymaganiem tylko wtedy, gdy trzeba? Więc twój b. js wygląda następująco
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
var a = require("./a"); //a.js has finished by now
util.log(a.property);
}
module.exports = ClassB;
Oczywiście dobrą praktyką jest umieszczanie wszystkich instrukcji require na wierzchu pliku. Ale są sytuacje, w których wybaczam sobie wybranie czegoś z innego modułu. Nazwij to hack, ale czasami jest to lepsze niż wprowadzenie dalszej zależności, dodanie dodatkowego modułu lub dodanie nowych struktur (EventEmitter, itp.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-17 13:36:28
Inną metodą, którą widziałem, jest eksportowanie w pierwszej linii i zapisywanie jej jako zmiennej lokalnej, takiej jak Ta:
let self = module.exports = {};
const a = require('./a');
// Exporting the necessary functions
self.func = function() { ... }
Używam tej metody, Czy wiesz o jej wadach?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 17:58:03
Właściwie to wymagałem uzależnienia od
var a = null;
process.nextTick(()=>a=require("./a")); //Circular reference!
Nie ładnie, ale działa. Jest to bardziej zrozumiałe i uczciwe niż zmiana b. js (na przykład tylko moduły rozszerzające.eksport), który w przeciwnym razie jest idealny jak jest.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-17 14:01:40
Podobne do odpowiedzi lanzza i setecta, używam następującego wzoru:
module.exports = Object.assign(module.exports, {
firstMember: ___,
secondMember: ___,
});
Object.assign()
kopiuje członków do obiektu exports
, który został już przekazany innym modułom.
Przypisanie =
jest logicznie zbędne, ponieważ jest tylko ustawieniem module.exports
dla siebie, ale używam go, ponieważ pomaga mojemu IDE (WebStorm) rozpoznać, że firstMember
jest właściwością tego modułu, więc "Go to -> Declaration" (Cmd-B) i inne narzędzia będą działać z innych narzędzi pliki.
Ten wzór nie jest zbyt ładny, więc używam go tylko wtedy, gdy trzeba rozwiązać problem cyklicznej zależności.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-05 04:40:51
Możesz to łatwo rozwiązać: po prostu wyeksportuj swoje dane, zanim będziesz potrzebować czegoś innego w modułach, w których używasz modułu."eksport": {]}
ClassA.js
class ClassA {
constructor(){
ClassB.someMethod();
ClassB.anotherMethod();
};
static someMethod () {
console.log( 'Class A Doing someMethod' );
};
static anotherMethod () {
console.log( 'Class A Doing anotherMethod' );
};
};
module.exports = ClassA;
var ClassB = require( "./classB.js" );
let classX = new ClassA();
ClassB.js
class ClassB {
constructor(){
ClassA.someMethod();
ClassA.anotherMethod();
};
static someMethod () {
console.log( 'Class B Doing someMethod' );
};
static anotherMethod () {
console.log( 'Class A Doing anotherMethod' );
};
};
module.exports = ClassB;
var ClassA = require( "./classA.js" );
let classX = new ClassB();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-30 09:10:19
Dla Twojego problemu możesz użyć deklaracji funkcji.
Class-b.js:
var ClassA = require('./class-a')
module.exports = ClassB
function ClassB() {
}
Class-a.js:
var classB = require('./class-b')
module.exports = ClassA
function ClassA() {
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-02 02:40:31