我在为firefox插件使用javascript代码模块时遇到了这种奇怪的行为。我不确定这是一个错误还是一个糟糕的相互导入设计。
假设有3个模块a、b和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 initn");
b.init();
}
};
b.js
var EXPORTED_SYMBOLS = ["b"];
Components.utils.import("resource://mymodule/c.js");
var b = {
init : function() {
try {
dump("B initn");
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()。现在有了上面的代码,我从b.中找到了一个未定义的"c">
A init
B init
Error C init : c is undefined
经过一些故障排除,我意识到要纠正这一点,
- 我可以交换a.js中的导入(b在c之前导入)
- 或者我可以删除相互导入(从c中删除b的导入)有了这两个,一切都会好起来
在我的实际代码中,b和c表示一些与UI相关的东西,它们具有相互依赖性。我可以完全取消模块的相互导入,并为其中一个模块注册回调函数。但我想知道是什么导致了这种行为。据我所知,文档中没有任何严格的模块间导入指南。我还知道,一个模块在多次导入时会被共享,因为模块的缓存。但不知怎的无法解释这一点。我在这里做错了什么?
我对正在发生的事情有一个理论,尽管我还没有尝试在调试器中运行代码以确保:
- a.js运行并导入c.js
- c.js运行并导入b.js(在定义
c
之前!) - b.js运行并导入c.js。但是c.js不会再次运行,因为它以前已经导入过一次
- 由于
c
在c.js作用域中仍然未定义(因为c.js
还没有继续运行;它仍在等待第2行的import
调用返回),因此c = undefined
被注入b.js范围 - b.js完成执行
- c.js完成执行
- .js完成执行
因此b.js从未接收到c
的有效绑定,并且b.init()
在尝试访问c.foo
时抛出异常。
如果这个理论是正确的,我认为您可以通过将b.js和c.js中的导入调用移动到这些文件的底部来修复错误。