Skip to content

Commit

Permalink
]firefox] Improve load time & behavior from suspended state
Browse files Browse the repository at this point in the history
Related issue:
uBlockOrigin/uBlock-issues#2969

Changes:

Use browser.alarms to trigger selfie creation. Presence of a selfie
improve markedly time to readiness when uBO is unsuspended.

Mirror content of storage.local to (in-memory) storage.session for
faster load to readiness when uBO is ususpended.
  • Loading branch information
gorhill committed Dec 4, 2023
1 parent a969a67 commit eb66820
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 12 deletions.
119 changes: 109 additions & 10 deletions platform/common/vapi-background.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,26 +87,111 @@ vAPI.app = {
},
};

/******************************************************************************/
/******************************************************************************/
/*******************************************************************************
*
* https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/storage/session
*
* Session (in-memory) storage is promise-based in all browsers, no need for
* a webext polyfill. However, not all browsers supports it in MV2.
*
* */

vAPI.sessionStorage = (( ) => {
if ( browser.storage.session instanceof Object === false ) {
return {
get() {
return Promise.resolve({});
},
set() {
return Promise.resolve();
},
remove() {
return Promise.resolve();
},
clear() {
return Promise.resolve();
},
implemented: false,
};
}
return {
get(...args) {
return browser.storage.session.get(...args).catch(reason => {
console.log(reason);
return {};
});
},
set(...args) {
return browser.storage.session.set(...args).catch(reason => {
console.log(reason);
});
},
remove(...args) {
return browser.storage.session.remove(...args).catch(reason => {
console.log(reason);
});
},
clear(...args) {
return browser.storage.session.clear(...args).catch(reason => {
console.log(reason);
});
},
implemented: true,
};
})();

/*******************************************************************************
*
* Data written to and read from storage.local will be mirrored to in-memory
* storage.session.
*
* Data read from storage.local will be first fetched from storage.session,
* then if not available, read from storage.local.
*
* */

vAPI.storage = {
get(...args) {
return webext.storage.local.get(...args).catch(reason => {
console.log(reason);
get(key, ...args) {
if ( vAPI.sessionStorage.implemented !== true ) {
return webext.storage.local.get(key, ...args).catch(reason => {
console.log(reason);
});
}
return vAPI.sessionStorage.get(key, ...args).then(bin => {
const size = Object.keys(bin).length;
if ( size === 1 && typeof key === 'string' && bin[key] === null ) {
return {};
}
if ( size !== 0 ) { return bin; }
return webext.storage.local.get(key, ...args).then(bin => {
if ( bin instanceof Object === false ) { return bin; }
// Mirror empty result as null value in order to prevent
// from falling back to storage.local when there is no need.
const tomirror = Object.assign({}, bin);
if ( typeof key === 'string' && Object.keys(bin).length === 0 ) {
Object.assign(tomirror, { [key]: null });
}
vAPI.sessionStorage.set(tomirror);
return bin;
}).catch(reason => {
console.log(reason);
});
});
},
set(...args) {
vAPI.sessionStorage.set(...args);
return webext.storage.local.set(...args).catch(reason => {
console.log(reason);
});
},
remove(...args) {
vAPI.sessionStorage.remove(...args);
return webext.storage.local.remove(...args).catch(reason => {
console.log(reason);
});
},
clear(...args) {
vAPI.sessionStorage.clear(...args);
return webext.storage.local.clear(...args).catch(reason => {
console.log(reason);
});
Expand Down Expand Up @@ -1422,14 +1507,14 @@ vAPI.adminStorage = (( ) => {
store = await webext.storage.managed.get();
} catch(ex) {
}
webext.storage.local.set({ cachedManagedStorage: store || {} });
vAPI.storage.set({ cachedManagedStorage: store || {} });
};

return {
get: async function(key) {
let bin;
try {
bin = await webext.storage.local.get('cachedManagedStorage') || {};
bin = await vAPI.storage.get('cachedManagedStorage') || {};
if ( Object.keys(bin).length === 0 ) {
bin = await webext.storage.managed.get() || {};
} else {
Expand Down Expand Up @@ -1477,7 +1562,7 @@ vAPI.localStorage = {
start: async function() {
if ( this.cache instanceof Promise ) { return this.cache; }
if ( this.cache instanceof Object ) { return this.cache; }
this.cache = webext.storage.local.get('localStorage').then(bin => {
this.cache = vAPI.storage.get('localStorage').then(bin => {
this.cache = bin instanceof Object &&
bin.localStorage instanceof Object
? bin.localStorage
Expand All @@ -1487,7 +1572,7 @@ vAPI.localStorage = {
},
clear: function() {
this.cache = {};
return webext.storage.local.set({ localStorage: this.cache });
return vAPI.storage.set({ localStorage: this.cache });
},
getItem: function(key) {
if ( this.cache instanceof Object === false ) {
Expand All @@ -1509,7 +1594,7 @@ vAPI.localStorage = {
await this.start();
if ( value === this.cache[key] ) { return; }
this.cache[key] = value;
return webext.storage.local.set({ localStorage: this.cache });
return vAPI.storage.set({ localStorage: this.cache });
},
cache: undefined,
};
Expand Down Expand Up @@ -1740,3 +1825,17 @@ vAPI.cloud = (( ) => {
})();

/******************************************************************************/
/******************************************************************************/

vAPI.alarms = browser.alarms || {
create() {
},
clear() {
},
onAlarm: {
addListener() {
}
}
};

/******************************************************************************/
1 change: 1 addition & 0 deletions platform/firefox/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
"open_in_tab": true
},
"permissions": [
"alarms",
"dns",
"menus",
"privacy",
Expand Down
2 changes: 2 additions & 0 deletions src/js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ if ( vAPI.webextFlavor.soup.has('firefox') ) {
}

const µBlock = { // jshint ignore:line
wakeupReason: '',

userSettingsDefault,
userSettings: Object.assign({}, userSettingsDefault),

Expand Down
16 changes: 14 additions & 2 deletions src/js/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
Home: https://github.com/gorhill/uBlock
*/

/* globals WebAssembly */

'use strict';

/******************************************************************************/
Expand Down Expand Up @@ -1243,6 +1241,8 @@ onBroadcast(msg => {
// memory usage at selfie-load time. For some reasons.

const create = async function() {
vAPI.alarms.clear('createSelfie');
createTimer.off();
if ( µb.inMemoryFilters.length !== 0 ) { return; }
if ( Object.keys(µb.availableFilterLists).length === 0 ) { return; }
await Promise.all([
Expand Down Expand Up @@ -1316,11 +1316,23 @@ onBroadcast(msg => {
io.remove(/^selfie\//);
µb.selfieIsInvalid = true;
}
if ( µb.wakeupReason === 'createSelfie' ) {
µb.wakeupReason = '';
return createTimer.offon({ sec: 27 });
}
vAPI.alarms.create('createSelfie', {
delayInMinutes: µb.hiddenSettings.selfieAfter
});
createTimer.offon({ min: µb.hiddenSettings.selfieAfter });
};

const createTimer = vAPI.defer.create(create);

vAPI.alarms.onAlarm.addListener(alarm => {
if ( alarm.name !== 'createSelfie') { return; }
µb.wakeupReason = 'createSelfie';
});

µb.selfieManager = { load, destroy };
}

Expand Down

1 comment on commit eb66820

@uBlock-user
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last time you used browser.alarms API, uBlockOrigin/uBlock-issues#2604 happened. So is that issue no longer an issue anymore?

Please sign in to comment.