In meinem System habe ich eine Reihe von "Klassen" in den Browser geladen, die während der Entwicklung jeweils separate Dateien enthalten und für die Produktion miteinander verkettet sind. Beim Laden initialisieren sie hier G
wie in diesem Beispiel eine Eigenschaft für ein globales Objekt :
var G = {};
G.Employee = function(name) {
this.name = name;
this.company = new G.Company(name + "'s own company");
};
G.Company = function(name) {
this.name = name;
this.employees = [];
};
G.Company.prototype.addEmployee = function(name) {
var employee = new G.Employee(name);
this.employees.push(employee);
employee.company = this;
};
var john = new G.Employee("John");
var bigCorp = new G.Company("Big Corp");
bigCorp.addEmployee("Mary");
Anstatt mein eigenes globales Objekt zu verwenden, denke ich darüber nach, jede Klasse zu einem eigenen AMD-Modul zu machen , basierend auf James Burkes Vorschlag :
define("Employee", ["Company"], function(Company) {
return function (name) {
this.name = name;
this.company = new Company(name + "'s own company");
};
});
define("Company", ["Employee"], function(Employee) {
function Company(name) {
this.name = name;
this.employees = [];
};
Company.prototype.addEmployee = function(name) {
var employee = new Employee(name);
this.employees.push(employee);
employee.company = this;
};
return Company;
});
define("main", ["Employee", "Company"], function (Employee, Company) {
var john = new Employee("John");
var bigCorp = new Company("Big Corp");
bigCorp.addEmployee("Mary");
});
Das Problem ist, dass es zuvor keine Abhängigkeit von der Deklarationszeit zwischen Mitarbeiter und Unternehmen gab: Sie konnten die Deklaration in die von Ihnen gewünschte Reihenfolge bringen, aber jetzt führt RequireJS eine Abhängigkeit ein, die hier (absichtlich) zirkulär ist Der obige Code schlägt fehl. Das addEmployee()
Hinzufügen einer ersten Zeile var Employee = require("Employee");
würde natürlich funktionieren , aber ich sehe diese Lösung als schlechter an, als RequireJS / AMD nicht zu verwenden, da ich als Entwickler diese neu erstellte zirkuläre Abhängigkeit kennen und etwas dagegen tun muss.
Gibt es eine bessere Möglichkeit, dieses Problem mit RequireJS / AMD zu lösen, oder verwende ich RequireJS / AMD für etwas, für das es nicht entwickelt wurde?
quelle
function(exports, Company)
undfunction(exports, Employee)
. Wie auch immer, danke für RequireJS, es ist großartig.Ich denke, dies ist ein ziemlicher Nachteil bei größeren Projekten, bei denen (mehrstufige) zirkuläre Abhängigkeiten unentdeckt bleiben. Mit madge können Sie jedoch eine Liste zirkulärer Abhängigkeiten drucken, um sich ihnen zu nähern.
quelle
Wenn Ihre Abhängigkeiten zu Beginn nicht geladen werden müssen (z. B. wenn Sie eine Klasse erweitern), können Sie Folgendes tun: (entnommen aus http://requirejs.org/docs/api.html# Rundschreiben )
In der Datei
a.js
:define( [ 'B' ], function( B ){ // Just an example return B.extend({ // ... }) });
Und in der anderen Datei
b.js
:define( [ ], function( ){ // Note that A is not listed var a; require(['A'], function( A ){ a = new A(); }); return function(){ functionThatDependsOnA: function(){ // Note that 'a' is not used until here a.doStuff(); } }; });
Im Beispiel des OP würde sich dies folgendermaßen ändern:
define("Employee", [], function() { var Company; require(["Company"], function( C ){ // Delayed loading Company = C; }); return function (name) { this.name = name; this.company = new Company(name + "'s own company"); }; }); define("Company", ["Employee"], function(Employee) { function Company(name) { this.name = name; this.employees = []; }; Company.prototype.addEmployee = function(name) { var employee = new Employee(name); this.employees.push(employee); employee.company = this; }; return Company; }); define("main", ["Employee", "Company"], function (Employee, Company) { var john = new Employee("John"); var bigCorp = new Company("Big Corp"); bigCorp.addEmployee("Mary"); });
quelle
Ich habe mir die Dokumente zu zirkulären Abhängigkeiten angesehen: http://requirejs.org/docs/api.html#circular
Wenn es eine zirkuläre Abhängigkeit mit a und b gibt, heißt es in Ihrem Modul, dass Sie als Abhängigkeit in Ihrem Modul Folgendes hinzufügen müssen:
define(["require", "a"],function(require, a) { ....
dann, wenn Sie "a" brauchen, rufen Sie einfach "a" wie folgt:
return function(title) { return require("a").doSomething(); }
Das hat bei mir funktioniert
quelle
Ich würde nur die zirkuläre Abhängigkeit vermeiden. Vielleicht so etwas wie:
G.Company.prototype.addEmployee = function(employee) { this.employees.push(employee); employee.company = this; }; var mary = new G.Employee("Mary"); var bigCorp = new G.Company("Big Corp"); bigCorp.addEmployee(mary);
Ich denke nicht, dass es eine gute Idee ist, dieses Problem zu umgehen und zu versuchen, die zirkuläre Abhängigkeit beizubehalten. Fühlt sich einfach wie allgemeine schlechte Praxis an. In diesem Fall kann es funktionieren, da Sie diese Module wirklich benötigen, wenn die exportierte Funktion aufgerufen wird. Stellen Sie sich jedoch den Fall vor, in dem Module benötigt und in den eigentlichen Definitionsfunktionen selbst verwendet werden. Keine Problemumgehung wird diese Arbeit machen. Dies ist wahrscheinlich der Grund, warum require.js bei der Erkennung kreisförmiger Abhängigkeiten in den Abhängigkeiten der Definitionsfunktion schnell fehlschlägt.
Wenn Sie wirklich eine Problemumgehung hinzufügen müssen, muss die sauberere IMO eine Abhängigkeit gerade noch rechtzeitig erfordern (in diesem Fall in Ihren exportierten Funktionen), dann werden die Definitionsfunktionen einwandfrei ausgeführt. Aber noch sauberer IMO ist nur, um zirkuläre Abhängigkeiten insgesamt zu vermeiden, was sich in Ihrem Fall sehr einfach anfühlt.
quelle
Alle veröffentlichten Antworten (außer https://stackoverflow.com/a/25170248/14731 ) sind falsch. Auch die offizielle Dokumentation (Stand November 2014) ist falsch.
Die einzige Lösung, die für mich funktioniert hat, besteht darin, eine "Gatekeeper" -Datei zu deklarieren und eine Methode zu definieren, die von den zirkulären Abhängigkeiten abhängt. Ein konkretes Beispiel finden Sie unter https://stackoverflow.com/a/26809254/14731 .
Hier ist, warum die oben genannten Lösungen nicht funktionieren.
var a; require(['A'], function( A ){ a = new A(); });
und später verwenden
a
, da es keine Garantie gibt, dass dieser Codeblock vor dem verwendeten Codeblock ausgeführt wirda
. (Diese Lösung ist irreführend, da sie in 90% der Fälle funktioniert.)exports
nicht für die gleiche Rennbedingung anfällig ist.Die Lösung hierfür lautet:
//module A define(['B'], function(b){ function A(b){ console.log(b)} return new A(b); //OK as is }); //module B define(['A'], function(a){ function B(a){} return new B(a); //wait...we can't do this! RequireJS will throw an error if we do this. }); //module B, new and improved define(function(){ function B(a){} return function(a){ //return a function which won't immediately execute return new B(a); } });
Jetzt können wir diese Module A und B in Modul C verwenden
//module C define(['A','B'], function(a,b){ var c = b(a); //executes synchronously (no race conditions) in other words, a is definitely defined before being passed to b });
quelle
In meinem Fall habe ich die zirkuläre Abhängigkeit gelöst, indem ich den Code des "einfacheren" Objekts in das komplexere verschoben habe. Für mich war das eine Sammlung und eine Modellklasse. Ich denke, in Ihrem Fall würde ich die mitarbeiterspezifischen Teile des Unternehmens zur Mitarbeiterklasse hinzufügen.
define("Employee", ["Company"], function(Company) { function Employee (name) { this.name = name; this.company = new Company(name + "'s own company"); }; Company.prototype.addEmployee = function(name) { var employee = new Employee(name); this.employees.push(employee); employee.company = this; }; return Employee; }); define("Company", [], function() { function Company(name) { this.name = name; this.employees = []; }; return Company; }); define("main", ["Employee", "Company"], function (Employee, Company) { var john = new Employee("John"); var bigCorp = new Company("Big Corp"); bigCorp.addEmployee("Mary"); });
Ein bisschen hacky, aber es sollte für einfache Fälle funktionieren. Und wenn Sie
addEmployee
einen Mitarbeiter als Parameter umgestalten , sollte die Abhängigkeit für Außenstehende noch offensichtlicher sein.quelle