为什么在Firefox Addon中导入的对象无法访问导入器的导入模块?

时间:2014-07-14 16:09:01

标签: javascript firefox-addon firefox-addon-restartless

为了澄清,请考虑以下简化示例:

one.js

Components.utils.import('resource://gre/modules/Services.jsm');

let obj = {

  init: function() {

   Components.utils.import('chrome://myaddon/modules/two.jsm', this);
  }

  // code here has access to Services.jsm
}

two.js

this.EXPORTED_SYMBOLS = ['abc'];

this.abc = {

  // abc is imported into obj()
  // however as part of obj (), abc{} does not have access to Services.jsm
}

我知道这是它的工作方式,但问题是为什么?
结果是,例如Services.jsm必须在每个模块中传授 虽然Firefox缓存模块并且没有太大的性能差异,但我想知道是否可以避免重复输入?

1 个答案:

答案 0 :(得分:2)

就像已经提到的@ felix-kling一样,这是由于模块级别的隔离,如果你考虑它会很有意义。如果不是这样,其他模块不仅会Services,还会abc

但还有另一个重要原因: 由于JS代码模块一次启动并在此之后进行缓存,如果您导入two.jsm两次,一次从已导入Services.jsm的模块导入,另一次从另一个模块导入{1}},会发生什么?现在two.jsm“看到”Services将取决于首先导入的其他模块!这将是非常讨厌的。

在这种情况下,您对“abc导入obj()”的评论是错误的。您的代码实际上将abc导入顶级范围。 Cu.import将始终导入顶级范围,除非您明确指定要导入的另一个范围。

"abc" in this; // false
"abc" in obj; // false
obj.init();
"abc" in this; // true
"abc" in obj; // false!

如果您想将two.jsm导入obj,则需要使用第二个参数调用Cu.import

let obj = {
  init: function() {
   Components.utils.import('chrome://myaddon/modules/two.jsm', this);
  }
};
"abc" in this; // false
"abc" in obj; // false
obj.init();
"abc" in this; // false
"abc" in obj; // true

但这当然不会影响Services的可见性。

我想,如果Cu.import只是自动导入了您要导入的某些模块,例如Services.jsmXPCOMUtils.jsm,那将会很有帮助。但由于遗留原因和向后兼容性限制,这不会也不会发生。 (例如,我有导入const {Promise} = Cu.import(..., {});的代码中断,因为ES6添加了一个默认的Promise全局...;这种向后兼容性问题/约束。)

替代?

嗯,显而易见的是不要将Cu.import用于自己的东西,而是使用别的东西。一堆附加组件,包括当然,所有SDK加载项都有自己的CommonJS样式require()实现。

  • 您可以在不使用SDK的情况下重新使用SDK加载程序,或者只使用SDK的选定部分(如果您愿意)。请参阅loader文档。我知道Erik在另一个非SDK Scriptish插件中创建了一个加载器。
  • 您可以根据下标加载器编写自己的自定义加载程序,也许Sandbox。例如。我在extSDK样板文件中这样做了(每个== loader.jsm::exports d模块都可以看到loader.jsm require中的所有全局符号。)

但这样做可能需要额外的工作,额外的知识和努力将现有的JS代码模块移植到基于require()的模块。