Javascript 奇怪的Gecko行为(试图在js模块之间传递nsiDomWindows数组)

Javascript 奇怪的Gecko行为(试图在js模块之间传递nsiDomWindows数组),javascript,debugging,firefox-addon,xpcom,gecko,Javascript,Debugging,Firefox Addon,Xpcom,Gecko,我正在编写一个引导firefox扩展。使用firefox开发者版v36.2a 我有两个似乎相关的问题,我不明白。第一,纯粹的烦恼: my bootstrap Console.utils.imports一个加载我的应用程序的js文件(创建名称空间对象并将所有其他js文件作为名称空间上的属性导入。所有其他文件都包含相同的名称空间文件,因此可以相互访问。它们甚至存储状态,所有内容的工作方式与节点缓存模块的方式非常相似,例如,似乎每个类中只有一个对象在整个系统中共享应用程序。现在,发生以下情况: 我的命

我正在编写一个引导firefox扩展。使用firefox开发者版v36.2a

我有两个似乎相关的问题,我不明白。第一,纯粹的烦恼:

my bootstrap Console.utils.imports一个加载我的应用程序的js文件(创建名称空间对象并将所有其他js文件作为名称空间上的属性导入。所有其他文件都包含相同的名称空间文件,因此可以相互访问。它们甚至存储状态,所有内容的工作方式与节点缓存模块的方式非常相似,例如,似乎每个类中只有一个对象在整个系统中共享应用程序。现在,发生以下情况:

我的命名空间文件执行以下操作:

namespace.console  = Components.utils.import( 'you know the one/console.jsm' )
namespace.Services = Components.utils.import( 'you know the one/Services.jsm')
namespace.Cu       = Components.utils
现在在另一个导入该文件的文件中,我得到了namespace对象,但是
namespace.Cu
将是未定义的。
console.log(namespace)
很好,但是它向我显示了Cu,我可以展开并查看它的所有属性等等……所有其他内容(控制台、服务、我自己的类)很好,但正在尝试从组件->未定义的Cc、Ci等

在我的应用程序的另一个地方,我有一个函数(在文件a中),它返回一个nsiDomWindows数组。文件B中的一个函数调用它,当它到达时,类似的故事:在控制台中,所有看起来都很好,我可以查看带有ChromeWidows的数组。但它实际上不再是一个数组,而是object和array[0]类型的数组未定义。如果我将两个类放在同一个文件中,它们就可以了

为了进一步混淆,我想我已经在另一个文件中使用了此方法,一切都很好:

// A.js
//
function A()
{
    b = new B()
    c = new C()

    let windows = b.windowList () // works fine, yields an actual valid array
                                  // with valid windows inside
    c.doSomething()               // broken, see below 
    c.doSomething( windows )      // passing it as a parameter 
                                  // doesn't help, still broken
}

// B.js
//
function B()
{
    this.windowList = function windowList()
    {
        let result = []

        // get open windows from nsiWindowMediator
        // foreach...
        // 
        result.push( nsiDomWindow )

        console.log( typeof result ) // Array -> it's completely valid here

        return result
    }
}


// C.js
//
function C()
{
    this.b = new B()


    this.doSomething = function doSomething( windows )
    {
        if( ! windows )

            windows = this.b.windowList()


        console.log( windows ) // in the console shows:
                               // Array[ ChromeWindow -> about:home ]
                               // I can inspect all it's properties, looks ok

        console.log( typeof windows )           // object
        console.log( windows.constructor.name ) // undefined

        console.log( windows[ 0 ]   )           // undefined

        // looping over the object properties shows that it does
        // have 1 property called '0' which points at undefined
        // note: there was only one open window in the array.
    }
}

// Note: the order in which I use Components.utils.import on these is B, C, A
我还想知道这是否与gecko中的安全措施有关,但在任何地方都看不到包装器对象,而且他们应该只屏蔽内容代码和chrome代码(这都是chrome代码)

正是这种bug让我感到沮丧,因为我想不出一个合理的理由来解释为什么函数的返回值在调用的两侧不应该是相同的

幸运的是,有一个解决办法,我会让我的make文件连接我所有的js文件,并一次性使用Components.utils。似乎我使用的mozilla API越少,我就越快乐,工作效率就越高

我也看到了来自mozilla代码的错误。我刚才有个错误说“shouldLog不是一个函数”在Console.jsm中。该函数在该文件的更高位置有明确定义。引发错误的行是一个正在返回的匿名函数。毫无疑问,该函数应该继承作用域,但事实并非如此。可能是某些内容正在破坏返回值,这与此相关

我提交了一个附加的示例插件,它演示了上面提到的第一个问题

更新

很抱歉,我混淆了两件事。我刚刚了解了Cu不可用的第一种情况下发生的情况。我只是加载了发生问题的文件,然后将Cu添加到我的命名空间中,因为我执行了const{console,Services,Cu}=全局作用域上的命名空间,这实际上是在创建属性之前计算的。令人困惑的是,控制台保留引用,而不是它显示给您的对象的副本(如果您问我,这是一个不幸的设计选择)在讨论中的代码之前记录名称空间,可以让您稍后查看它的状态,我没有考虑到这一点

这仍然不能解释一个函数如何向接收其他内容的接收函数返回一个完美的值,或者在Console.jsm中声明的函数如何不再存在于继承其作用域的函数中

总而言之,第一个问题与其他问题没有任何关系。但是,我无法创建一个可复制的小插件来说明其他2个问题。如果我想办法,我会上传它

顺便说一句:控制台的陷阱很容易看到(将以下内容放在javascript草稿行中):

出于调试目的(通常是主要目的),控制台有其局限性,通常最好在调试器中设置断点或使用
JSON。stringify

我没有全部阅读,但: 我认为第一个问题是你输入错误

如果要将其带到从Cu.import导出的变量的某个命名空间中,应按以下方式执行:

Cu.进口resource://gre/modules/ctypes.jsm,命名空间)

不需要var blah=Cu.import

Console.jsm和Services.jsm导出一个名为te的var,并使用相同的东西

你甚至可以只做Cu.importrsource://gre/modules/ctypes.jsm)并开始像ctypes.blah一样使用它

要访问Cu,请执行以下操作:

var {Cu: utils, Cr: results} = Components

接下来,我认为如果您在一个作用域中更改模块,它在其他作用域中不会更改,直到您在该作用域中再次执行Cu.import。

我认为我已经将前面提到的所有问题缩小到了无法正确卸载的范围。我有一些我没有删除的事件侦听器,当它们触发时,对象或作用域可能会失效

使用扩展自动安装程序在某种程度上使这些问题更加严重,因为在加载项未正确卸载时重新加载加载项会造成加载项代码的不可靠状态

shouldLog不是一个函数,因为我认为我必须卸载使用Components.utils.unload加载的所有模块,所以我卸载了Console.jsm

修复后,再加上将所有入口点包装到我的软件中的try-catch块中,现在运行起来更加顺畅。我现在很少需要卸载插件并在更新代码后重新启动firefox


没有什么比几天的调试更有趣的了…

感谢您的关注。我知道有不同的导入方法,它们都可以工作,这不是问题所在。我没有传递名称空间来导入的原因是控制台(例如导出)也有我不需要的控制台API。不过,我解决了第一个问题,但事实并非如此与其他问题相同。我在更新中描述了这一点。
var {Cu: utils, Cr: results} = Components