Reputation: 713
I have been working on a context-menu that communicates with a page mod and come up against an issue.
I am able to send a communication with right click to the page / tab in view as long as I do not refresh the page. When I refresh the page a new worker is created and the context menu cannot communicate with the worker.
I now have two identical workers but it is like the old one has expired. That means this loop in onMessage: does not work because it picks up the first worker.
for (index = 0; index < workers.length; index += 1) {
if (workers[index].tab.index === tabs.activeTab.index) {
workers[index].port.emit("rightClick", string, ss.storage.product);
}
}
I have been looking to remove the old worker on refresh but there seems to be no option to do so. Am I fundamentally missing something about the handling of workers?
The error I receive is: Error: The page is currently hidden and can no longer be used until it is visible again.
This is consistent with the fact that as far as the worker is concerned I am now looking at a new page in the same tab. I thought worker.on('detach', function(){}) was supposed to handle this but it seems this is only on the closing of the tab.
Any advice would be appreciated.
added OK after a little break I decided to use the detachWorker function recommended elsewhere for detach. I placed it at the top of my pageMod object as below
// Clean up duplicate worker
for (index in workers) {
if(workers[index].url === worker.url && workers[index].tab.index === worker.tab.index) {
detachWorker(workers[index], workers);
}
}
This fixes the issue (for now) although I don't think it is the correct approach. Any advances on a solution :).
Upvotes: 4
Views: 1397
Reputation: 24150
Ran into this too. The Worker objects seem to stick around for some past pages (and reused when going Back and Forward in history). The solution is to listen to the pagehide
and pageshow
events so as to only keep the currently shown workers in the array:
var pageMod = require("sdk/page-mod");
var array = require('sdk/util/array');
var pageWorkers = [];
pageMod.PageMod({
onAttach: function(worker) {
array.add(pageWorkers, worker);
worker.on('pageshow', function() { array.add(pageWorkers, this); });
worker.on('pagehide', function() { array.remove(pageWorkers, this); });
worker.on('detach', function() { array.remove(pageWorkers, this); });
// do other work.
}
});
Note that array.add
function takes care of not adding duplicates.
Upvotes: 6
Reputation: 210
ZERO is right, the event detach
is emitted on reload.
But when I open a different page in the same tab no detach-event is been emitted!
So, i.e., when I have loaded some page A in tab 1 and click on a link which opens a different page B in the same tab 1 I have to detach the worker for page A manually(?)
var workers = [];
require('page-mod').PageMod({
include: '*',
contentScriptWhen: 'end',
contentScript: [require('self').data.url('bla.js')],
onAttach: function(worker) {
var w = workers.length;
while (w--) {
if (worker.tab === workers[w].tab) {
workers.splice(w, 1);
break;
}
}
workers.push(worker);
// other stuff
}
});
Upvotes: 0
Reputation: 25332
Not sure I got your problem. The event you mentioned, detach, is also emitted when a the tab is reloaded:
const { add, remove } = require("sdk/util/array");
const workers = [];
require("sdk/page-mod").PageMod({
include: "*",
contentScript: "alert('executed')",
onAttach: function(worker) {
add(workers, worker);
console.log('attached: ', workers.length);
worker.on('detach', function() {
remove(workers, worker);
console.log('detached: ', workers.length);
})
}
});
When I reload the page the detach's listener is executed. Anyway, to check if a tab's associate to the worker is the active's tab you should be able to compare just the tab object: (workers[index].tab === tabs.activeTab)
. Notice also that in Add-on SDK 1.14 tabs have also the id
property, so you can use it to identify themselves.
And the for…in
loop for index is not reccomended: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/for...in check the description section. I would rather use the for…of:
for (let worker of workers) { ... }
Upvotes: 1