mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-22 16:29:09 +01:00
Ensure chrome.storage listeners also get cleaned up in Safari to avoid memory leak (#6354)
This commit is contained in:
parent
5d14afb97f
commit
5b69d52f02
@ -199,7 +199,10 @@ export class BrowserApi {
|
|||||||
BrowserApi.removeTab(tabToClose.id);
|
BrowserApi.removeTab(tabToClose.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep track of all the events registered in a Safari popup so we can remove
|
||||||
|
// them when the popup gets unloaded, otherwise we cause a memory leak
|
||||||
private static registeredMessageListeners: any[] = [];
|
private static registeredMessageListeners: any[] = [];
|
||||||
|
private static registeredStorageChangeListeners: any[] = [];
|
||||||
|
|
||||||
static messageListener(
|
static messageListener(
|
||||||
name: string,
|
name: string,
|
||||||
@ -207,19 +210,36 @@ export class BrowserApi {
|
|||||||
) {
|
) {
|
||||||
chrome.runtime.onMessage.addListener(callback);
|
chrome.runtime.onMessage.addListener(callback);
|
||||||
|
|
||||||
// Keep track of all the events registered in a Safari popup so we can remove
|
|
||||||
// them when the popup gets unloaded, otherwise we cause a memory leak
|
|
||||||
if (BrowserApi.isSafariApi && !BrowserApi.isBackgroundPage(window)) {
|
if (BrowserApi.isSafariApi && !BrowserApi.isBackgroundPage(window)) {
|
||||||
BrowserApi.registeredMessageListeners.push(callback);
|
BrowserApi.registeredMessageListeners.push(callback);
|
||||||
|
BrowserApi.setupUnloadListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static storageChangeListener(
|
||||||
|
callback: Parameters<typeof chrome.storage.onChanged.addListener>[0]
|
||||||
|
) {
|
||||||
|
chrome.storage.onChanged.addListener(callback);
|
||||||
|
|
||||||
|
if (BrowserApi.isSafariApi && !BrowserApi.isBackgroundPage(window)) {
|
||||||
|
BrowserApi.registeredStorageChangeListeners.push(callback);
|
||||||
|
BrowserApi.setupUnloadListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the event to destroy all the listeners when the popup gets unloaded in Safari, otherwise we get a memory leak
|
||||||
|
private static setupUnloadListeners() {
|
||||||
// The MDN recommend using 'visibilitychange' but that event is fired any time the popup window is obscured as well
|
// The MDN recommend using 'visibilitychange' but that event is fired any time the popup window is obscured as well
|
||||||
// 'pagehide' works just like 'unload' but is compatible with the back/forward cache, so we prefer using that one
|
// 'pagehide' works just like 'unload' but is compatible with the back/forward cache, so we prefer using that one
|
||||||
window.onpagehide = () => {
|
window.onpagehide = () => {
|
||||||
for (const callback of BrowserApi.registeredMessageListeners) {
|
for (const callback of BrowserApi.registeredMessageListeners) {
|
||||||
chrome.runtime.onMessage.removeListener(callback);
|
chrome.runtime.onMessage.removeListener(callback);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
for (const callback of BrowserApi.registeredStorageChangeListeners) {
|
||||||
|
chrome.storage.onChanged.removeListener(callback);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static sendMessage(subscriber: string, arg: any = {}) {
|
static sendMessage(subscriber: string, arg: any = {}) {
|
||||||
|
@ -14,6 +14,7 @@ import { Account } from "../../models/account";
|
|||||||
import { BrowserComponentState } from "../../models/browserComponentState";
|
import { BrowserComponentState } from "../../models/browserComponentState";
|
||||||
import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState";
|
import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState";
|
||||||
import { BrowserSendComponentState } from "../../models/browserSendComponentState";
|
import { BrowserSendComponentState } from "../../models/browserSendComponentState";
|
||||||
|
import { BrowserApi } from "../browser/browser-api";
|
||||||
import { browserSession, sessionSync } from "../decorators/session-sync-observable";
|
import { browserSession, sessionSync } from "../decorators/session-sync-observable";
|
||||||
|
|
||||||
import { BrowserStateService as StateServiceAbstraction } from "./abstractions/browser-state.service";
|
import { BrowserStateService as StateServiceAbstraction } from "./abstractions/browser-state.service";
|
||||||
@ -56,7 +57,7 @@ export class BrowserStateService
|
|||||||
// the background page that can get out of sync. We need to work out the
|
// the background page that can get out of sync. We need to work out the
|
||||||
// best way to handle caching with multiple instances of the state service.
|
// best way to handle caching with multiple instances of the state service.
|
||||||
if (useAccountCache) {
|
if (useAccountCache) {
|
||||||
chrome.storage.onChanged.addListener((changes, namespace) => {
|
BrowserApi.storageChangeListener((changes, namespace) => {
|
||||||
if (namespace === "local") {
|
if (namespace === "local") {
|
||||||
for (const key of Object.keys(changes)) {
|
for (const key of Object.keys(changes)) {
|
||||||
if (key !== "accountActivity" && this.accountDiskCache.value[key]) {
|
if (key !== "accountActivity" && this.accountDiskCache.value[key]) {
|
||||||
|
Loading…
Reference in New Issue
Block a user