Javascript Firefox加载项pageshow事件在worker能够接收消息之前触发

Javascript Firefox加载项pageshow事件在worker能够接收消息之前触发,javascript,firefox,firefox-addon,firefox-addon-sdk,Javascript,Firefox,Firefox Addon,Firefox Addon Sdk,我正在编写一个firefox插件,并在一个数组中跟踪每个页面的工作人员。除了这里和这里描述的管理阵列所需的一些花哨的步法之外,一切都正常工作。我遇到的一个问题是,在收听tabs pageshow事件或worker自己的pageshow事件时,回调似乎在worker实际准备就绪之前启动。在回调中检索页面的对应工作程序并使用它尝试向内容脚本发送消息时,我收到错误消息该页面当前处于隐藏状态,在再次可见之前无法再使用。通常,我会使用setTimeout并咬紧牙关,但这不适用于附加组件。什么是合适的解决方

我正在编写一个firefox插件,并在一个数组中跟踪每个页面的工作人员。除了这里和这里描述的管理阵列所需的一些花哨的步法之外,一切都正常工作。我遇到的一个问题是,在收听tabs pageshow事件或worker自己的pageshow事件时,回调似乎在worker实际准备就绪之前启动。在回调中检索页面的对应工作程序并使用它尝试向内容脚本发送消息时,我收到错误消息该页面当前处于隐藏状态,在再次可见之前无法再使用。通常,我会使用setTimeout并咬紧牙关,但这不适用于附加组件。什么是合适的解决方法?附件主要部分的代码如下:

var { ToggleButton } = require('sdk/ui/button/toggle');
var panels = require('sdk/panel');
var tabs = require('sdk/tabs');
var self = require('sdk/self');
var pageMods = require('sdk/page-mod');
var ss = require('sdk/simple-storage');
var workers = [];

ss.storage.isPluginActive = ss.storage.isPluginActive || false;

var button = ToggleButton({
    id: 'tomorrowww',
    label: 'Tomorowww',
    icon: {
        '16': './icon-16.png',
        '32': './icon-32.png',
        '64': './icon-64.png'
    },
    onChange: handleButtonChange
});

var panel = panels.Panel({
    contentURL: self.data.url('panel.html'),
    contentScriptFile: self.data.url('panel-script.js'),
    onHide: handlePanelHide,
    width: 342,
    height: 270
});

panel.port.on('panel-ready', handlePanelReady);
panel.port.on('plugin-toggled', handlePluginToggled);
panel.port.on('link-clicked', handleLinkClicked);

pageMods.PageMod({
    include: ['*'],
    contentScriptFile: [self.data.url('CancerDOMManager.js'), self.data.url('content-script.js')],
    contentStyleFile: self.data.url('content-style.css'),
    onAttach: function (worker) {
        addWorker(worker);
        sendActiveState(ss.storage.isPluginActive);
    }
});

// move between tabs
tabs.on('activate', function () {
    sendActiveState();
});

// this actually fires before the worker's pageshow event so isn't useful as the workers array will be out of sync
//tabs.on('pageshow', function () {
//    sendActiveState();
//});

function addWorker (worker) {
    if(workers.indexOf(worker) > -1) {
        return;
    }

    worker.on('detach', handleWorkerDetach);
    worker.on('pageshow', handleWorkerShown);
    worker.on('pagehide', handleWorkerHidden);
    workers.push(worker);
}

function handleWorkerDetach () {
    removeWorker(this, true);
}

function handleWorkerShown () {
    addWorker(this);

    // back / forward page history
    // trying to send the state here will trigger the page hidden error
    sendActiveState();
}

function handleWorkerHidden () {
    removeWorker(this);
}

function removeWorker (worker, removeEvents) {
    var index = workers.indexOf(worker);

    removeEvents = removeEvents || false;

    if(index > -1) {
        if(removeEvents) {
            worker.removeListener('detach', handleWorkerDetach);
            worker.removeListener('pageshow', handleWorkerShown);
            worker.removeListener('pagehide', handleWorkerHidden);
        }

        workers.splice(index, 1);
    }
}

function getWorkersForCurrentTab () {
    var i;
    var tabWorkers = [];

    i = workers.length;

    while(--i > -1) {
        if(workers[i].tab.id === tabs.activeTab.id) {
            tabWorkers.push(workers[i]);
        }
    }

    return tabWorkers;
}

function handlePanelReady () {
    setActive(ss.storage.isPluginActive);
}

function setActive (bool) {
    ss.storage.isPluginActive = bool;
    panel.port.emit('active-changed', bool);
    sendActiveState();
}

function sendActiveState () {
    var tabWorkers = getWorkersForCurrentTab();
    var i = tabWorkers.length;

    while(--i > -1) {
        tabWorkers[i].port.emit('toggle-plugin', ss.storage.isPluginActive);
    }
}

function handleButtonChange (state) {
    if(state.checked) {
        panel.show({
            position: button
        });
    }
}

function handlePanelHide () {
    button.state('window', {checked: false});
}

function handleLinkClicked (url) {
    if(panel.isShowing) {
        panel.hide();
    }

    tabs.open(url);
}

function handlePluginToggled (bool) {
    if(panel.isShowing) {
        panel.hide();
    }

    setActive(bool);
}

尝试使用contentScriptWhen:start页面mod

我正在处理类似的问题。我想我现在已经按照我想要的方式工作了,将侦听器放在内容脚本而不是加载项脚本中。我在窗口上侦听事件,然后从我的内容脚本向我的加载项脚本发送消息,然后我的加载项脚本向内容脚本发送一条消息,其中包含加载项脚本所需的信息

在我的代码中,我正在更新内容脚本中的首选项,以确保选项卡在更改时始终具有最新的设置,只有加载项脚本可以侦听prefs更改事件

当页面从历史记录(即后退或前进按钮)导航到时,此特定代码段将侦听,并通知加载项脚本,加载项脚本将获取最新的首选项,然后将它们发送回内容脚本中侦听的端口

内容脚本: 加载项脚本,例如main.js:
由于事件是从DOM事件触发的,因此必须显示该页面。我不确定在加载项脚本中收听pageshow事件是否符合我们的想法。

似乎setTimeout可用,只需要sdk/timers模块要求它。尽管如此,这仍然是一个非常可怕的解决方案……我也遇到了类似的问题,从“准备就绪”到“开始”的更改并没有阻止页面出现问题,即页面仍然隐藏。
window.onpageshow = function(){
    console.log("onpageshow event fired (content script)");
    self.port.emit("triggerPrefChange", '');    
};
worker.port.on("triggerPrefChange", function() {
      console.log("Received request to triggerPrefChange in the addon script");
      worker.port.emit("setPrefs", prefSet.prefs);
  });