Comment gérer les dépendances circulaires avec RequireJS/AMD?
Dans mon système, j'ai un certain nombre de "classes" chargé dans le navigateur de chaque un des fichiers séparés au cours du développement, et concaténées pour la production. Comme ils sont chargés, ils initialiser une propriété sur un objet global, ici G
, comme dans cet exemple:
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");
Au lieu d'utiliser mon propre objet global, j'envisage de faire de chaque classe à ses propres AMD module, basé sur James Burke suggestion:
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");
});
Le problème est qu'avant, il n'y avait pas de déclarer dépendance entre l'Employé et de l'Entreprise: vous pouvez mettre de la déclaration, dans l'ordre que vous voulais, mais maintenant, à l'aide de RequireJS, ce qui introduit une dépendance, qui est ici (intentionnellement) circulaire, de sorte que le code ci-dessus échoue. Bien sûr, dans addEmployee()
, l'ajout d'une première ligne de var Employee = require("Employee");
serait le faire fonctionner, mais je ne vois que cette solution comme inférieurs à pas à l'aide de RequireJS/AMD car il exige de moi, le développeur, d'être conscient de cette nouvelle circulaire de la dépendance et de faire quelque chose à ce sujet.
Est-il une meilleure façon de résoudre ce problème avec RequireJS/AMD, ou suis-je à l'aide de RequireJS/AMD pour quelque chose, il n'a pas été conçu pour?
Vous devez vous connecter pour publier un commentaire.
C'est en effet une restriction de l'AMD format. Vous pouvez utiliser les exportations, et que le problème disparaît. - Je trouver les exportations d'être moche, mais c'est la manière dont les CommonJS modules de résoudre le problème:
Sinon, le besoin("Employee") que vous mentionnez dans votre message serait trop de travail.
En général avec les modules dont vous avez besoin pour être plus conscient de dépendances circulaires, AMD ou pas. Même dans la plaine, JavaScript, vous devez être sûr d'utiliser un objet comme le G de l'objet dans votre exemple.
function(exports, Company)
etfunction(exports, Employee)
. De toute façon, merci pour RequireJS, c'est géniale.Je pense que c'est un inconvénient dans les grands projets où (multi-niveau) dépendances circulaires demeurer inaperçue.
Cependant, avec madge vous pouvez imprimer une liste de dépendances circulaires de les approcher.
Si vous n'avez pas besoin de vos dépendances être chargé au démarrage (par exemple, lorsque vous êtes extension d'une classe), alors c'est ce que vous pouvez faire: (prises de http://requirejs.org/docs/api.html#circular)
Dans le fichier
a.js
:Et dans l'autre fichier
b.js
:Dans le cas des OP exemple, c'est comment il allait modifier:
Je voudrais juste éviter la dépendance circulaire. Peut-être quelque chose comme:
Je ne pense pas que c'est une bonne idée pour contourner ce problème et essayer de garder la dépendance circulaire. Juste l'impression générale d'une mauvaise pratique. Dans ce cas, il peut travailler parce que vous avez vraiment besoin de ces modules pour quand la fonction exportée est appelé. Mais imaginer le cas où les modules sont requis et utilisés dans les fonctions de définition de lui-même. Aucune solution de contournement permettra de faire ce travail. C'est probablement pourquoi require.js échoue rapide sur la dépendance circulaire de détection dans les dépendances de la définition de la fonction.
Si vous avez vraiment pour ajouter un travail autour de, le propre de l'OMI est d'exiger une dépendance de juste à temps (dans vos fonctions exportées dans ce cas), puis la définition de fonctions de fonctionner correctement. Mais encore plus propre de l'OMI est juste pour éviter des dépendances circulaires au total, qui se sent vraiment facile à faire dans votre cas.
Toutes les réponses (sauf https://stackoverflow.com/a/25170248/14731) sont erronées. Même la documentation officielle (en novembre 2014) est erroné.
La seule solution qui a fonctionné pour moi est de déclarer un "gatekeeper" fichier, et de définir une méthode qui repose sur les dépendances circulaires. Voir https://stackoverflow.com/a/26809254/14731 pour un exemple concret.
Ici, c'est pourquoi les solutions ci-dessus ne fonctionnera pas.
et ensuite utiliser
a
plus tard, car il n'y a aucune garantie que ce bloc de code sera exécuté avant le bloc de code qui utilisea
. (Cette solution est trompeuse, car elle fonctionne 90% du temps)exports
n'est pas vulnérable à la même condition de course.la solution à cela est:
maintenant, nous pouvons utiliser ces modules A et B dans le module C
J'ai regardé les docs sur les dépendances circulaires :http://requirejs.org/docs/api.html#circular
Si il y a une dépendance circulaire avec a et b , il est dit dans votre module pour ajouter exiger, comme une dépendance dans votre module comme suit :
puis, quand vous avez besoin de "un" appel "a" de la sorte:
Cela a fonctionné pour moi
Dans mon cas, j'ai résolu le problème de la dépendance circulaire en déplaçant le code de la "simple" objet le plus complexe. Pour moi c'était une collecte et une classe de modèle. Je suppose que dans votre cas, je voudrais ajouter l'Employé parties spécifiques de la Société dans la classe d'Employés.
Très orthodoxe, mais il devrait fonctionner pour les cas simples. Et si vous refactoriser
addEmployee
de prendre un Employé en tant que paramètre, la dépendance devrait être encore plus évident pour les étrangers.