简体   繁体   中英

Dojo cyclic dependency using require

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,

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.

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:

  • A depends on B
  • A depends on C
  • B depends on C

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM