Skip to content

Commit 879b272

Browse files
authored
Merge pull request #864 from quoid/fix/863/content-scripts-memory-leak
fix: avoid browser tabs content scripts memory leak
2 parents 73112a9 + 7e9301b commit 879b272

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

src/ext/content-scripts/entry-script-market.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ async function injection() {
99
);
1010
}
1111
for (const link of links) {
12+
if (link["href"]) url = link["href"];
1213
link.addEventListener(
1314
"click",
1415
(e) => {
15-
url = link["href"];
1616
e.stopImmediatePropagation();
1717
e.preventDefault();
1818
browser.runtime.sendMessage({ name: "WEB_USERJS_POPUP" });
@@ -23,14 +23,27 @@ async function injection() {
2323
}
2424

2525
async function listeners() {
26-
browser.runtime.onMessage.addListener(async (message) => {
26+
/**
27+
* handle messages from background, popup, etc...
28+
* @type {import("webextension-polyfill").Runtime.OnMessageListener}
29+
*/
30+
const handleMessage = async (message) => {
2731
if (import.meta.env.MODE === "development") {
2832
console.debug(message, url);
2933
}
3034
if (message === "TAB_CLICK_USERJS") {
31-
const response = url;
32-
url = undefined; // respond only once of click event
33-
return response;
35+
return url;
36+
}
37+
};
38+
/** Dynamically remove listeners to avoid memory leaks */
39+
if (document.visibilityState === "visible") {
40+
browser.runtime.onMessage.addListener(handleMessage);
41+
}
42+
document.addEventListener("visibilitychange", () => {
43+
if (document.hidden) {
44+
browser.runtime.onMessage.removeListener(handleMessage);
45+
} else {
46+
browser.runtime.onMessage.addListener(handleMessage);
3447
}
3548
});
3649
}

src/ext/content-scripts/entry-userscripts.js

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,23 @@ function triageJS(userscript) {
2525
if (document.readyState !== "loading") {
2626
injectJS(userscript);
2727
} else {
28-
document.addEventListener("DOMContentLoaded", () => {
29-
injectJS(userscript);
30-
});
28+
document.addEventListener(
29+
"DOMContentLoaded",
30+
() => injectJS(userscript),
31+
{ once: true },
32+
);
3133
}
3234
} else if (runAt === "document-idle") {
3335
if (document.readyState === "complete") {
3436
injectJS(userscript);
3537
} else {
36-
document.addEventListener("readystatechange", () => {
38+
const handle = () => {
3739
if (document.readyState === "complete") {
3840
injectJS(userscript);
41+
document.removeEventListener("readystatechange", handle);
3942
}
40-
});
43+
};
44+
document.addEventListener("readystatechange", handle);
4145
}
4246
}
4347
}
@@ -233,17 +237,23 @@ async function injection() {
233237
}
234238

235239
function listeners() {
236-
// listens for messages from background, popup, etc...
237-
browser.runtime.onMessage.addListener((request) => {
238-
const name = request.name;
240+
/** listen for CSP violations */
241+
document.addEventListener("securitypolicyviolation", cspFallback, {
242+
once: true,
243+
});
244+
/**
245+
* listens for messages from background, popup, etc...
246+
* @type {import("webextension-polyfill").Runtime.OnMessageListener}
247+
*/
248+
const handleMessage = (message) => {
249+
const name = message.name;
239250
if (name === "CONTEXT_RUN") {
240251
// from bg script when context-menu item is clicked
241252
// double check to ensure context-menu scripts only run in top windows
242253
if (window !== window.top) return;
243-
244254
// loop through context-menu scripts saved to data object and find match
245255
// if no match found, nothing will execute and error will log
246-
const filename = request.menuItemId;
256+
const filename = message.menuItemId;
247257
for (let i = 0; i < data.files.menu.length; i++) {
248258
const item = data.files.menu[i];
249259
if (item.scriptObject.filename === filename) {
@@ -254,9 +264,18 @@ function listeners() {
254264
}
255265
console.error(`Couldn't find ${filename} code!`);
256266
}
267+
};
268+
/** Dynamically remove listeners to avoid memory leaks */
269+
if (document.visibilityState === "visible") {
270+
browser.runtime.onMessage.addListener(handleMessage);
271+
}
272+
document.addEventListener("visibilitychange", () => {
273+
if (document.hidden) {
274+
browser.runtime.onMessage.removeListener(handleMessage);
275+
} else {
276+
browser.runtime.onMessage.addListener(handleMessage);
277+
}
257278
});
258-
// listen for CSP violations
259-
document.addEventListener("securitypolicyviolation", cspFallback);
260279
}
261280

262281
async function initialize() {

0 commit comments

Comments
 (0)