Question

I came across this strange behavior while using javascript code modules for a firefox addon. I'm not sure if this is a bug or a bad design doing mutual imports.

So let's say there are 3 modules a, b and c.

a.js

var EXPORTED_SYMBOLS = ["a"];                                                       
Components.utils.import("resource://mymodule/c.js");                                 
Components.utils.import("resource://mymodule/b.js");                                 

var a = {                                                                           
    init: function() {                                                              
        dump("A init\n");                                                           
        b.init();                                                                   
    }                                                                               
};     

b.js

var EXPORTED_SYMBOLS = ["b"];
Components.utils.import("resource://mymodule/c.js");

var b = {
    init : function() {
        try {
            dump("B init\n");
            dump(c.foo() + "\n");
        } catch (e) {
            dump("Error C init : " + e.message + "\n");
        }
    }
};

c.js

var EXPORTED_SYMBOLS = ["c"];
Components.utils.import("resource://mymodule/b.js");

var c = {
    foo : function() {
        return "C Foo";
    },
};

a.init() is called externally. Now with the above code, I hit an undefined for 'c' from b.

A init
B init
Error C init : c is undefined

After some troubleshooting, I realized that to correct this,

  • I can either swap the imports inside a.js (b is imported before c)
  • Or I can remove the mutual import ( remove the import of b from within c) With either of these, things go fine.

In my actual code b and c represent some UI related stuff and they have mutual dependencies. I can totally get rid of a mutual import of modules, and register a callback function for one of them. But I wish to know what is causing this behavior. As far as I understand the documentation do not have any strict guidelines for import among modules. I am also aware that one module when imported multiple times will be shared because of caching of modules. But somehow can't explain this. What am I doing wrong here ?

Was it helpful?

Solution

I have a theory about what is happening, though I haven't tried running the code in a debugger to make sure:

  • a.js runs and imports c.js
  • c.js runs and imports b.js (before c is defined!)
  • b.js runs and imports c.js. But c.js does not run again, because it has already been imported once before.
  • Since c is still undefined in the c.js scope (because c.js has not continued running yet; it is still waiting for the import call on line 2 to return), c = undefined is injected into the b.js scope.
  • b.js finishes executing.
  • c.js finishes executing.
  • a.js finishes executing.

So b.js never receives a valid binding for c, and b.init() throws an exception when it tries to access c.foo.

If this theory is correct, I think you could fix the error by moving the import calls in b.js and c.js to the bottoms of those files.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top