Reputation: 1652
I'm using dojo and these are my modules -
'myview/ModuleA' --requires--> 'myview/ModuleB'
'myview/ModuleB' --requires--> 'myview/ModuleC'
'myview/ModuleC' --requires--> 'myview/ModuleD'
Now, I'm trying to make
'myview/ModuleD' --requires--> 'myview/ModuleB'
But the code fails in ModuleD when it tries to instantiate ModuleB
as new ModuleB ()
with TypeError: ModuleB is not a constructor
.
I see that ModuleB
is just an object
and not a function
in ModuleD
when it is trying to instantiate it. So I know why I get the error. I also realize this is probably because of cyclic dependency and that's the reason ModuleB
is not loaded in ModuleD
.
I was able to work around this by removing ModuleB
from the requires list in the define(...)
of ModuleD
and instead load it using require()
just before it is instantiated. This works.
My Question - Is this the right way of doing something that involves cyclic dependency of modules or is there a better/different way that is recommended?
Thanks,
Upvotes: 0
Views: 438
Reputation: 44755
Even though RequireJS has a proper workaround for circular dependencies like this:
//Inside b.js:
define(["require", "a"],
function(require, a) {
//"a" in this case will be null if "a" also asked for "b",
//a circular dependency.
return function(title) {
return require("a").doSomething();
}
}
);
(Source)
Using circular dependencies often* means that you have a design that should be improved. Having 2 modules that depend on each other means that you have a highly coupled design, which should ring a bell in every developers brains. Read this for more information: https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references
The proper solution would be that if A depends on B and B depends on A, is that all code that B uses from A is separated in a different module, which we call C. We can then decouple the modules like this:
And there you have it, you have decoupled your code by using an intermediator.
* Cyclic dependencies are not always bad though, for example, if you have a Company
that has Employee
's, then you could also say that you have an Employee
that works within a Company
. In this case you would have a circular dependency as well, and then you can use the approach described above.
Upvotes: 1
Reputation: 3568
Requiring "on the fly" instead of doing it a define
time is the proper approach for circular dependencies.
This is explained here: http://requirejs.org/docs/api.html#circular
If you define a circular dependency ("a" needs "b" and "b" needs "a"), then in this case when "b"'s module function is called, it will get an undefined value for "a". "b" can fetch "a" later after modules have been defined by using the require() method (be sure to specify require as a dependency so the right context is used to look up "a")
Important: At build time, you will have to specify in the build profile all components you had to require on the fly. Otherwise they will not be included in the list of files to build.
Upvotes: 1