1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-10-04 16:47:15 +02:00

Wrap usage of setTimeout in helper for background + auxiliary pages

This commit centralizes usage of setTimeout()/clearTimeout() in the
source code at one single location.
This commit is contained in:
Raymond Hill 2023-04-09 13:38:16 -04:00
parent b4984ed85b
commit 91f9795023
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
23 changed files with 365 additions and 420 deletions

View File

@ -35,6 +35,116 @@ vAPI.T0 = Date.now();
vAPI.setTimeout = vAPI.setTimeout || self.setTimeout.bind(self); vAPI.setTimeout = vAPI.setTimeout || self.setTimeout.bind(self);
vAPI.defer = {
create(callback) {
return new this.Client(callback);
},
once(delay, ...args) {
const delayInMs = vAPI.defer.normalizeDelay(delay);
return new Promise(resolve => {
vAPI.setTimeout(
(...args) => { resolve(...args); },
delayInMs,
...args
);
});
},
Client: class {
constructor(callback) {
this.timer = null;
this.type = 0;
this.callback = callback;
}
on(delay, ...args) {
if ( this.timer !== null ) { return; }
const delayInMs = vAPI.defer.normalizeDelay(delay);
this.type = 0;
this.timer = vAPI.setTimeout(( ) => {
this.timer = null;
this.callback(...args);
}, delayInMs || 1);
}
offon(delay, ...args) {
this.off();
this.on(delay, ...args);
}
onvsync(delay, ...args) {
if ( this.timer !== null ) { return; }
const delayInMs = vAPI.defer.normalizeDelay(delay);
if ( delayInMs !== 0 ) {
this.type = 0;
this.timer = vAPI.setTimeout(( ) => {
this.timer = null;
this.onraf(...args);
}, delayInMs);
} else {
this.onraf(...args);
}
}
onidle(delay, ...args) {
if ( this.timer !== null ) { return; }
const delayInMs = vAPI.defer.normalizeDelay(delay);
if ( delayInMs !== 0 ) {
this.type = 0;
this.timer = vAPI.setTimeout(( ) => {
this.timer = null;
this.onric(...args);
}, delayInMs);
} else {
this.onric(...args);
}
}
off() {
if ( this.timer === null ) { return; }
switch ( this.type ) {
case 0:
self.clearTimeout(this.timer);
break;
case 1:
self.cancelAnimationFrame(this.timer);
break;
case 2:
self.cancelIdleCallback(this.timer);
break;
default:
break;
}
this.timer = null;
}
onraf(...args) {
if ( this.timer !== null ) { return; }
this.type = 1;
this.timer = requestAnimationFrame(( ) => {
this.timer = null;
this.callback(...args);
});
}
onric(...args) {
if ( this.timer !== null ) { return; }
this.type = 2;
this.timer = self.requestIdleCallback(deadline => {
this.timer = null;
this.callback(deadline, ...args);
});
}
ongoing() {
return this.timer !== null;
}
},
normalizeDelay(delay = 0) {
if ( typeof delay === 'object' ) {
if ( delay.sec !== undefined ) {
return delay.sec * 1000;
} else if ( delay.min !== undefined ) {
return delay.min * 60000;
} else if ( delay.hr !== undefined ) {
return delay.hr * 3600000;
}
}
return delay;
}
};
/******************************************************************************/ /******************************************************************************/
vAPI.webextFlavor = { vAPI.webextFlavor = {

View File

@ -56,12 +56,17 @@ let cachedUserFilters = '';
/******************************************************************************/ /******************************************************************************/
// Add auto-complete ability to the editor. // Add auto-complete ability to the editor. Polling is used as the suggested
// hints also depend on the tabs currently opened.
{ {
let hintUpdateToken = 0; let hintUpdateToken = 0;
const responseHandler = function(response) { const getHints = async function() {
const response = await vAPI.messaging.send('dashboard', {
what: 'getAutoCompleteDetails',
hintUpdateToken
});
if ( response instanceof Object === false ) { return; } if ( response instanceof Object === false ) { return; }
if ( response.hintUpdateToken !== undefined ) { if ( response.hintUpdateToken !== undefined ) {
const mode = cmEditor.getMode(); const mode = cmEditor.getMode();
@ -73,15 +78,12 @@ let cachedUserFilters = '';
} }
hintUpdateToken = response.hintUpdateToken; hintUpdateToken = response.hintUpdateToken;
} }
vAPI.setTimeout(getHints, 2503); timer.on(2503);
}; };
const getHints = function() { const timer = vAPI.defer.create(( ) => {
vAPI.messaging.send('dashboard', { getHints();
what: 'getAutoCompleteDetails', });
hintUpdateToken
}).then(responseHandler);
};
getHints(); getHints();
} }
@ -306,8 +308,7 @@ dom.on('#userFiltersRevert', 'click', revertChanges);
// https://github.com/gorhill/uBlock/issues/3706 // https://github.com/gorhill/uBlock/issues/3706
// Save/restore cursor position // Save/restore cursor position
{ {
const line = const line = await vAPI.localStorage.getItemAsync('myFiltersCursorPosition');
await vAPI.localStorage.getItemAsync('myFiltersCursorPosition');
if ( typeof line === 'number' ) { if ( typeof line === 'number' ) {
cmEditor.setCursor(line, 0); cmEditor.setCursor(line, 0);
} }
@ -317,15 +318,14 @@ dom.on('#userFiltersRevert', 'click', revertChanges);
// Save/restore cursor position // Save/restore cursor position
{ {
let curline = 0; let curline = 0;
let timer;
cmEditor.on('cursorActivity', ( ) => { cmEditor.on('cursorActivity', ( ) => {
if ( timer !== undefined ) { return; } if ( timer.ongoing() ) { return; }
if ( cmEditor.getCursor().line === curline ) { return; } if ( cmEditor.getCursor().line === curline ) { return; }
timer = vAPI.setTimeout(( ) => { timer.on(701);
timer = undefined; });
curline = cmEditor.getCursor().line; const timer = vAPI.defer.create(( ) => {
vAPI.localStorage.setItem('myFiltersCursorPosition', curline); curline = cmEditor.getCursor().line;
}, 701); vAPI.localStorage.setItem('myFiltersCursorPosition', curline);
}); });
} }

View File

@ -118,19 +118,16 @@ const arrayFromString = function(s) {
/******************************************************************************/ /******************************************************************************/
const advancedSettingsChanged = (( ) => { const advancedSettingsChanged = (( ) => {
let timer;
const handler = ( ) => { const handler = ( ) => {
timer = undefined; const changed = hashFromAdvancedSettings(cmEditor.getValue()) !== beforeHash;
const changed =
hashFromAdvancedSettings(cmEditor.getValue()) !== beforeHash;
qs$('#advancedSettingsApply').disabled = !changed; qs$('#advancedSettingsApply').disabled = !changed;
CodeMirror.commands.save = changed ? applyChanges : function(){}; CodeMirror.commands.save = changed ? applyChanges : function(){};
}; };
const timer = vAPI.defer.create(handler);
return function() { return function() {
if ( timer !== undefined ) { clearTimeout(timer); } timer.offon(200);
timer = vAPI.setTimeout(handler, 100);
}; };
})(); })();

View File

@ -73,20 +73,16 @@ assets.fetch = function(url, options = {}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// Start of executor // Start of executor
const timeoutAfter = µb.hiddenSettings.assetFetchTimeout * 1000 || 30000; const timeoutAfter = µb.hiddenSettings.assetFetchTimeout || 30;
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
let contentLoaded = 0; let contentLoaded = 0;
let timeoutTimer;
const cleanup = function() { const cleanup = function() {
xhr.removeEventListener('load', onLoadEvent); xhr.removeEventListener('load', onLoadEvent);
xhr.removeEventListener('error', onErrorEvent); xhr.removeEventListener('error', onErrorEvent);
xhr.removeEventListener('abort', onErrorEvent); xhr.removeEventListener('abort', onErrorEvent);
xhr.removeEventListener('progress', onProgressEvent); xhr.removeEventListener('progress', onProgressEvent);
if ( timeoutTimer !== undefined ) { timeoutTimer.off();
clearTimeout(timeoutTimer);
timeoutTimer = undefined;
}
}; };
const fail = function(details, msg) { const fail = function(details, msg) {
@ -130,12 +126,11 @@ assets.fetch = function(url, options = {}) {
const onProgressEvent = function(ev) { const onProgressEvent = function(ev) {
if ( ev.loaded === contentLoaded ) { return; } if ( ev.loaded === contentLoaded ) { return; }
contentLoaded = ev.loaded; contentLoaded = ev.loaded;
if ( timeoutTimer !== undefined ) { timeoutTimer.offon({ sec: timeoutAfter });
clearTimeout(timeoutTimer);
}
timeoutTimer = vAPI.setTimeout(onTimeout, timeoutAfter);
}; };
const timeoutTimer = vAPI.defer.create(onTimeout);
// Be ready for thrown exceptions: // Be ready for thrown exceptions:
// I am pretty sure it used to work, but now using a URL such as // I am pretty sure it used to work, but now using a URL such as
// `file:///` on Chromium 40 results in an exception being thrown. // `file:///` on Chromium 40 results in an exception being thrown.
@ -147,7 +142,7 @@ assets.fetch = function(url, options = {}) {
xhr.addEventListener('progress', onProgressEvent); xhr.addEventListener('progress', onProgressEvent);
xhr.responseType = options.responseType || 'text'; xhr.responseType = options.responseType || 'text';
xhr.send(); xhr.send();
timeoutTimer = vAPI.setTimeout(onTimeout, timeoutAfter); timeoutTimer.on({ sec: timeoutAfter });
} catch (e) { } catch (e) {
onErrorEvent.call(xhr); onErrorEvent.call(xhr);
} }
@ -422,17 +417,14 @@ const unregisterAssetSource = function(assetKey) {
}; };
const saveAssetSourceRegistry = (( ) => { const saveAssetSourceRegistry = (( ) => {
let timer; const save = ( ) => {
const save = function() { timer.off();
timer = undefined;
cacheStorage.set({ assetSourceRegistry }); cacheStorage.set({ assetSourceRegistry });
}; };
const timer = vAPI.defer.create(save);
return function(lazily) { return function(lazily) {
if ( timer !== undefined ) {
clearTimeout(timer);
}
if ( lazily ) { if ( lazily ) {
timer = vAPI.setTimeout(save, 500); timer.offon(500);
} else { } else {
save(); save();
} }
@ -533,15 +525,14 @@ const getAssetCacheRegistry = function() {
}; };
const saveAssetCacheRegistry = (( ) => { const saveAssetCacheRegistry = (( ) => {
let timer;
const save = function() { const save = function() {
timer = undefined; timer.off();
cacheStorage.set({ assetCacheRegistry }); cacheStorage.set({ assetCacheRegistry });
}; };
const timer = vAPI.defer.create(save);
return function(lazily) { return function(lazily) {
if ( timer !== undefined ) { clearTimeout(timer); }
if ( lazily ) { if ( lazily ) {
timer = vAPI.setTimeout(save, 30000); timer.offon({ sec: 30 });
} else { } else {
save(); save();
} }
@ -961,7 +952,6 @@ const updaterUpdated = [];
const updaterFetched = new Set(); const updaterFetched = new Set();
let updaterStatus; let updaterStatus;
let updaterTimer;
let updaterAssetDelay = updaterAssetDelayDefault; let updaterAssetDelay = updaterAssetDelayDefault;
let updaterAuto = false; let updaterAuto = false;
@ -1043,9 +1033,11 @@ const updateNext = async function() {
fireNotification('asset-update-failed', { assetKey: result.assetKey }); fireNotification('asset-update-failed', { assetKey: result.assetKey });
} }
vAPI.setTimeout(updateNext, updaterAssetDelay); updaterTimer.on(updaterAssetDelay);
}; };
const updaterTimer = vAPI.defer.create(updateNext);
const updateDone = function() { const updateDone = function() {
const assetKeys = updaterUpdated.slice(0); const assetKeys = updaterUpdated.slice(0);
updaterFetched.clear(); updaterFetched.clear();
@ -1064,8 +1056,7 @@ assets.updateStart = function(details) {
updaterAuto = details.auto === true; updaterAuto = details.auto === true;
if ( updaterStatus !== undefined ) { if ( updaterStatus !== undefined ) {
if ( newUpdateDelay < oldUpdateDelay ) { if ( newUpdateDelay < oldUpdateDelay ) {
clearTimeout(updaterTimer); updaterTimer.offon(updaterAssetDelay);
updaterTimer = vAPI.setTimeout(updateNext, updaterAssetDelay);
} }
return; return;
} }
@ -1073,10 +1064,7 @@ assets.updateStart = function(details) {
}; };
assets.updateStop = function() { assets.updateStop = function() {
if ( updaterTimer ) { updaterTimer.off();
clearTimeout(updaterTimer);
updaterTimer = undefined;
}
if ( updaterStatus !== undefined ) { if ( updaterStatus !== undefined ) {
updateDone(); updateDone();
} }

View File

@ -172,7 +172,6 @@ const µBlock = { // jshint ignore:line
allowedRequestCount: 0, allowedRequestCount: 0,
}, },
localSettingsLastModified: 0, localSettingsLastModified: 0,
localSettingsLastSaved: 0,
// Read-only // Read-only
systemSettings: { systemSettings: {

View File

@ -69,18 +69,13 @@ import {
const loadBenchmarkDataset = (( ) => { const loadBenchmarkDataset = (( ) => {
let datasetPromise; let datasetPromise;
let ttlTimer;
const ttlTimer = vAPI.defer.create(( ) => {
datasetPromise = undefined;
});
return function() { return function() {
if ( ttlTimer !== undefined ) { ttlTimer.offon({ min: 5 });
clearTimeout(ttlTimer);
ttlTimer = undefined;
}
setTimeout(( ) => {
ttlTimer = undefined;
datasetPromise = undefined;
}, 5 * 60 * 1000);
if ( datasetPromise !== undefined ) { if ( datasetPromise !== undefined ) {
return datasetPromise; return datasetPromise;

View File

@ -101,36 +101,27 @@ const cacheStorage = {
const selectIDB = async function() { const selectIDB = async function() {
let db; let db;
let dbPromise; let dbPromise;
let dbTimer;
const noopfn = function () { const noopfn = function () {
}; };
const disconnect = function() { const disconnect = function() {
if ( dbTimer !== undefined ) { dbTimer.off();
clearTimeout(dbTimer);
dbTimer = undefined;
}
if ( db instanceof IDBDatabase ) { if ( db instanceof IDBDatabase ) {
db.close(); db.close();
db = undefined; db = undefined;
} }
}; };
const dbTimer = vAPI.defer.create(( ) => {
disconnect();
});
const keepAlive = function() { const keepAlive = function() {
if ( dbTimer !== undefined ) { dbTimer.offon(Math.max(
clearTimeout(dbTimer); µb.hiddenSettings.autoUpdateAssetFetchPeriod * 2 * 1000,
} 180000
dbTimer = vAPI.setTimeout( ));
( ) => {
dbTimer = undefined;
disconnect();
},
Math.max(
µb.hiddenSettings.autoUpdateAssetFetchPeriod * 2 * 1000,
180000
)
);
}; };
// https://github.com/gorhill/uBlock/issues/3156 // https://github.com/gorhill/uBlock/issues/3156
@ -192,13 +183,13 @@ const selectIDB = async function() {
resolve(null); resolve(null);
resolve = undefined; resolve = undefined;
}; };
setTimeout(( ) => { vAPI.defer.once(5000).then(( ) => {
if ( resolve === undefined ) { return; } if ( resolve === undefined ) { return; }
db = null; db = null;
dbPromise = undefined; dbPromise = undefined;
resolve(null); resolve(null);
resolve = undefined; resolve = undefined;
}, 5000); });
}); });
return dbPromise; return dbPromise;
}; };

View File

@ -211,7 +211,7 @@ async function setURL(resourceURL) {
dom.attr(a, 'title', afterURL); dom.attr(a, 'title', afterURL);
addPastURLs(afterURL); addPastURLs(afterURL);
// For unknown reasons, calling focus() synchronously does not work... // For unknown reasons, calling focus() synchronously does not work...
vAPI.setTimeout(( ) => { cmEditor.focus(); }, 1); vAPI.defer.once(1).then(( ) => { cmEditor.focus(); });
} }
/******************************************************************************/ /******************************************************************************/

View File

@ -86,16 +86,7 @@ import { i18n$ } from '../i18n.js';
return; return;
} }
if ( queryTextFromSearchWidget(cm) === state.queryText ) { return; } if ( queryTextFromSearchWidget(cm) === state.queryText ) { return; }
if ( state.queryTimer !== null ) { state.queryTimer.offon(350);
clearTimeout(state.queryTimer);
}
state.queryTimer = setTimeout(
() => {
state.queryTimer = null;
findCommit(cm, 0);
},
350
);
}; };
const searchWidgetClickHandler = function(cm, ev) { const searchWidgetClickHandler = function(cm, ev) {
@ -141,7 +132,6 @@ import { i18n$ } from '../i18n.js';
this.panel = cm.addPanel(this.widget); this.panel = cm.addPanel(this.widget);
} }
this.queryText = ''; this.queryText = '';
this.queryTimer = null;
this.dirty = true; this.dirty = true;
this.lines = []; this.lines = [];
cm.on('changes', (cm, changes) => { cm.on('changes', (cm, changes) => {
@ -155,6 +145,9 @@ import { i18n$ } from '../i18n.js';
cm.on('cursorActivity', cm => { cm.on('cursorActivity', cm => {
updateCount(cm); updateCount(cm);
}); });
this.queryTimer = vAPI.defer.create(( ) => {
findCommit(cm, 0);
});
}; };
// We want the search widget to behave as if the focus was on the // We want the search widget to behave as if the focus was on the
@ -426,10 +419,7 @@ import { i18n$ } from '../i18n.js';
const findCommit = function(cm, dir) { const findCommit = function(cm, dir) {
const state = getSearchState(cm); const state = getSearchState(cm);
if ( state.queryTimer !== null ) { state.queryTimer.off();
clearTimeout(state.queryTimer);
state.queryTimer = null;
}
const queryText = queryTextFromSearchWidget(cm); const queryText = queryTextFromSearchWidget(cm);
if ( queryText === state.queryText ) { return; } if ( queryText === state.queryText ) { return; }
state.queryText = queryText; state.queryText = queryText;

View File

@ -111,19 +111,15 @@ const relaxBlockingMode = (( ) => {
if ( noReload ) { return; } if ( noReload ) { return; }
// Reload: use a timer to coalesce bursts of reload commands. // Reload: use a timer to coalesce bursts of reload commands.
let timer = reloadTimers.get(tab.id); const timer = reloadTimers.get(tab.id) || (( ) => {
if ( timer !== undefined ) { const t = vAPI.defer.create(tabId => {
clearTimeout(timer);
}
timer = vAPI.setTimeout(
tabId => {
reloadTimers.delete(tabId); reloadTimers.delete(tabId);
vAPI.tabs.reload(tabId); vAPI.tabs.reload(tabId);
}, });
547, reloadTimers.set(tab.id, t);
tab.id return t;
); })();
reloadTimers.set(tab.id, timer); timer.offon(547, tab.id);
}; };
})(); })();

View File

@ -225,10 +225,12 @@ const FilterContainer = function() {
this.reSimpleHighGeneric = /^(?:[a-z]*\[[^\]]+\]|\S+)$/; this.reSimpleHighGeneric = /^(?:[a-z]*\[[^\]]+\]|\S+)$/;
this.selectorCache = new Map(); this.selectorCache = new Map();
this.selectorCachePruneDelay = 10 * 60 * 1000; // 10 minutes this.selectorCachePruneDelay = 10; // 10 minutes
this.selectorCacheCountMin = 40; this.selectorCacheCountMin = 40;
this.selectorCacheCountMax = 50; this.selectorCacheCountMax = 50;
this.selectorCacheTimer = null; this.selectorCacheTimer = vAPI.defer.create(( ) => {
this.pruneSelectorCacheAsync();
});
// specific filters // specific filters
this.specificFilters = new StaticExtFilteringHostnameDB(2); this.specificFilters = new StaticExtFilteringHostnameDB(2);
@ -274,10 +276,7 @@ FilterContainer.prototype.reset = function() {
this.duplicateBuster = new Set(); this.duplicateBuster = new Set();
this.selectorCache.clear(); this.selectorCache.clear();
if ( this.selectorCacheTimer !== null ) { this.selectorCacheTimer.off();
clearTimeout(this.selectorCacheTimer);
this.selectorCacheTimer = null;
}
// hostname, entity-based filters // hostname, entity-based filters
this.specificFilters.clear(); this.specificFilters.clear();
@ -604,18 +603,6 @@ FilterContainer.prototype.fromSelfie = function(selfie) {
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.triggerSelectorCachePruner = function() {
// Of interest: http://fitzgeraldnick.com/weblog/40/
// http://googlecode.blogspot.ca/2009/07/gmail-for-mobile-html5-series-using.html
if ( this.selectorCacheTimer !== null ) { return; }
this.selectorCacheTimer = vAPI.setTimeout(
( ) => { this.pruneSelectorCacheAsync(); },
this.selectorCachePruneDelay
);
};
/******************************************************************************/
FilterContainer.prototype.addToSelectorCache = function(details) { FilterContainer.prototype.addToSelectorCache = function(details) {
const hostname = details.hostname; const hostname = details.hostname;
if ( typeof hostname !== 'string' || hostname === '' ) { return; } if ( typeof hostname !== 'string' || hostname === '' ) { return; }
@ -626,7 +613,7 @@ FilterContainer.prototype.addToSelectorCache = function(details) {
entry = SelectorCacheEntry.factory(); entry = SelectorCacheEntry.factory();
this.selectorCache.set(hostname, entry); this.selectorCache.set(hostname, entry);
if ( this.selectorCache.size > this.selectorCacheCountMax ) { if ( this.selectorCache.size > this.selectorCacheCountMax ) {
this.triggerSelectorCachePruner(); this.selectorCacheTimer.on({ min: this.selectorCachePruneDelay });
} }
} }
entry.add(details); entry.add(details);
@ -658,7 +645,6 @@ FilterContainer.prototype.removeFromSelectorCache = function(
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.pruneSelectorCacheAsync = function() { FilterContainer.prototype.pruneSelectorCacheAsync = function() {
this.selectorCacheTimer = null;
if ( this.selectorCache.size <= this.selectorCacheCountMax ) { return; } if ( this.selectorCache.size <= this.selectorCacheCountMax ) { return; }
const cache = this.selectorCache; const cache = this.selectorCache;
const hostnames = Array.from(cache.keys()) const hostnames = Array.from(cache.keys())

View File

@ -113,18 +113,18 @@ self.uBlockDashboard.dateNowToSensibleString = function() {
/******************************************************************************/ /******************************************************************************/
self.uBlockDashboard.patchCodeMirrorEditor = (function() { self.uBlockDashboard.patchCodeMirrorEditor = (function() {
let grabFocusTimer;
let grabFocusTarget; let grabFocusTarget;
const grabFocus = function() { const grabFocus = function() {
grabFocusTarget.focus(); grabFocusTarget.focus();
grabFocusTimer = grabFocusTarget = undefined; grabFocusTarget = undefined;
}; };
const grabFocusTimer = vAPI.defer.create(grabFocus);
const grabFocusAsync = function(cm) { const grabFocusAsync = function(cm) {
grabFocusTarget = cm; grabFocusTarget = cm;
if ( grabFocusTimer === undefined ) { grabFocusTimer.on(1);
grabFocusTimer = vAPI.setTimeout(grabFocus, 1);
}
}; };
// https://github.com/gorhill/uBlock/issues/3646 // https://github.com/gorhill/uBlock/issues/3646

View File

@ -104,19 +104,19 @@ if ( self.location.hash.slice(1) === 'no-dashboard.html' ) {
(async ( ) => { (async ( ) => {
// Wait for uBO's main process to be ready // Wait for uBO's main process to be ready
await new Promise(resolve => { await new Promise(resolve => {
const check = ( ) => { const check = async ( ) => {
vAPI.messaging.send('dashboard', { try {
what: 'readyToFilter' const response = await vAPI.messaging.send('dashboard', {
}).then(response => { what: 'readyToFilter'
});
if ( response ) { return resolve(true); } if ( response ) { return resolve(true); }
const iframe = qs$('#iframe'); const iframe = qs$('#iframe');
if ( iframe.src !== '' ) { if ( iframe.src !== '' ) {
iframe.src = ''; iframe.src = '';
} }
vAPI.setTimeout(check, 250); } catch(ex) {
}).catch(( ) => { }
vAPI.setTimeout(check, 250); vAPI.defer.once(250).then(( ) => check());
});
}; };
check(); check();
}); });

View File

@ -336,39 +336,35 @@ const startDialog = (function() {
let textarea; let textarea;
let hideSelectors = []; let hideSelectors = [];
let unhideSelectors = []; let unhideSelectors = [];
let inputTimer;
const onInputChanged = (function() { const parse = function() {
const parse = function() { hideSelectors = [];
inputTimer = undefined; unhideSelectors = [];
hideSelectors = [];
unhideSelectors = [];
const re = /^([^#]*)(#@?#)(.+)$/; const re = /^([^#]*)(#@?#)(.+)$/;
for ( let line of textarea.value.split(/\s*\n\s*/) ) { for ( let line of textarea.value.split(/\s*\n\s*/) ) {
line = line.trim(); line = line.trim();
if ( line === '' || line.charAt(0) === '!' ) { continue; } if ( line === '' || line.charAt(0) === '!' ) { continue; }
const matches = re.exec(line); const matches = re.exec(line);
if ( matches === null || matches.length !== 4 ) { continue; } if ( matches === null || matches.length !== 4 ) { continue; }
if ( inspectedHostname.lastIndexOf(matches[1]) === -1 ) { if ( inspectedHostname.lastIndexOf(matches[1]) === -1 ) {
continue; continue;
}
if ( matches[2] === '##' ) {
hideSelectors.push(matches[3]);
} else {
unhideSelectors.push(matches[3]);
}
} }
if ( matches[2] === '##' ) {
showCommitted(); hideSelectors.push(matches[3]);
}; } else {
unhideSelectors.push(matches[3]);
return function parseAsync() {
if ( inputTimer === undefined ) {
inputTimer = vAPI.setTimeout(parse, 743);
} }
}; }
})();
showCommitted();
};
const inputTimer = vAPI.defer.create(parse);
const onInputChanged = ( ) => {
inputTimer.on(743);
};
const onClicked = function(ev) { const onClicked = function(ev) {
var target = ev.target; var target = ev.target;
@ -433,10 +429,7 @@ const startDialog = (function() {
}; };
const stop = function() { const stop = function() {
if ( inputTimer !== undefined ) { inputTimer.off();
clearTimeout(inputTimer);
inputTimer = undefined;
}
showInteractive(); showInteractive();
textarea.removeEventListener('input', onInputChanged); textarea.removeEventListener('input', onInputChanged);
dialog.removeEventListener('click', onClicked, true); dialog.removeEventListener('click', onClicked, true);
@ -513,11 +506,9 @@ const onClicked = function(ev) {
/******************************************************************************/ /******************************************************************************/
const onMouseOver = (function() { const onMouseOver = (function() {
var mouseoverTarget = null; let mouseoverTarget = null;
var mouseoverTimer = null;
var timerHandler = function() { const timerHandler = ( ) => {
mouseoverTimer = null;
vAPI.MessagingConnection.sendTo(inspectorConnectionId, { vAPI.MessagingConnection.sendTo(inspectorConnectionId, {
what: 'highlightOne', what: 'highlightOne',
selector: selectorFromNode(mouseoverTarget), selector: selectorFromNode(mouseoverTarget),
@ -526,21 +517,17 @@ const onMouseOver = (function() {
}); });
}; };
const mouseoverTimer = vAPI.defer.create(timerHandler);
return function(ev) { return function(ev) {
if ( inspectedTabId === 0 ) { return; } if ( inspectedTabId === 0 ) { return; }
// Convenience: skip real-time highlighting if shift key is pressed. // Convenience: skip real-time highlighting if shift key is pressed.
if ( ev.shiftKey ) { return; } if ( ev.shiftKey ) { return; }
// Find closest `li` // Find closest `li`
var target = ev.target; const target = ev.target.closest('li');
while ( target !== null ) {
if ( target.localName === 'li' ) { break; }
target = target.parentElement;
}
if ( target === mouseoverTarget ) { return; } if ( target === mouseoverTarget ) { return; }
mouseoverTarget = target; mouseoverTarget = target;
if ( mouseoverTimer === null ) { mouseoverTimer.on(50);
mouseoverTimer = vAPI.setTimeout(timerHandler, 50);
}
}; };
})(); })();

View File

@ -567,8 +567,6 @@ const viewPort = (( ) => {
let wholeHeight = 0; let wholeHeight = 0;
let lastTopPix = 0; let lastTopPix = 0;
let lastTopRow = 0; let lastTopRow = 0;
let scrollTimer;
let resizeTimer;
const ViewEntry = function() { const ViewEntry = function() {
this.div = document.createElement('div'); this.div = document.createElement('div');
@ -602,19 +600,10 @@ const viewPort = (( ) => {
}; };
// Coalesce scroll events // Coalesce scroll events
const onScroll = function() { const scrollTimer = vAPI.defer.create(onScrollChanged);
if ( scrollTimer !== undefined ) { return; } const onScroll = ( ) => {
scrollTimer = setTimeout( scrollTimer.onvsync(1000/32);
( ) => {
scrollTimer = requestAnimationFrame(( ) => {
scrollTimer = undefined;
onScrollChanged();
});
},
1000/32
);
}; };
dom.on(vwScroller, 'scroll', onScroll, { passive: true }); dom.on(vwScroller, 'scroll', onScroll, { passive: true });
const onLayoutChanged = function() { const onLayoutChanged = function() {
@ -721,19 +710,10 @@ const viewPort = (( ) => {
updateContent(0); updateContent(0);
}; };
const resizeTimer = vAPI.defer.create(onLayoutChanged);
const updateLayout = function() { const updateLayout = function() {
if ( resizeTimer !== undefined ) { return; } resizeTimer.onvsync(1000/8);
resizeTimer = setTimeout(
( ) => {
resizeTimer = requestAnimationFrame(( ) => {
resizeTimer = undefined;
onLayoutChanged();
});
},
1000/8
);
}; };
dom.on(window, 'resize', updateLayout, { passive: true }); dom.on(window, 'resize', updateLayout, { passive: true });
updateLayout(); updateLayout();
@ -1128,10 +1108,13 @@ const onLogBufferRead = function(response) {
/******************************************************************************/ /******************************************************************************/
const readLogBuffer = (( ) => { const readLogBuffer = (( ) => {
let timer; let reading = false;
const readLogBufferNow = async function() { const readLogBufferNow = async function() {
if ( logger.ownerId === undefined ) { return; } if ( logger.ownerId === undefined ) { return; }
if ( reading ) { return; }
reading = true;
const msg = { const msg = {
what: 'readAll', what: 'readAll',
@ -1159,20 +1142,20 @@ const readLogBuffer = (( ) => {
const response = await vAPI.messaging.send('loggerUI', msg); const response = await vAPI.messaging.send('loggerUI', msg);
timer = undefined;
onLogBufferRead(response); onLogBufferRead(response);
readLogBufferLater();
reading = false;
timer.on(1200);
}; };
const readLogBufferLater = function() { const timer = vAPI.defer.create(readLogBufferNow);
if ( timer !== undefined ) { return; }
if ( logger.ownerId === undefined ) { return; }
timer = vAPI.setTimeout(readLogBufferNow, 1200);
};
readLogBufferNow(); readLogBufferNow();
return readLogBufferLater; return ( ) => {
timer.on(1200);
};
})(); })();
/******************************************************************************/ /******************************************************************************/
@ -2203,17 +2186,13 @@ const rowFilterer = (( ) => {
}; };
const onFilterChangedAsync = (( ) => { const onFilterChangedAsync = (( ) => {
let timer;
const commit = ( ) => { const commit = ( ) => {
timer = undefined;
parseInput(); parseInput();
filterAll(); filterAll();
}; };
const timer = vAPI.defer.create(commit);
return ( ) => { return ( ) => {
if ( timer !== undefined ) { timer.offon(750);
clearTimeout(timer);
}
timer = vAPI.setTimeout(commit, 750);
}; };
})(); })();
@ -2290,7 +2269,7 @@ const rowJanitor = (( ) => {
let rowIndex = 0; let rowIndex = 0;
const discard = function(timeRemaining) { const discard = function(deadline) {
const opts = loggerSettings.discard; const opts = loggerSettings.discard;
const maxLoadCount = typeof opts.maxLoadCount === 'number' const maxLoadCount = typeof opts.maxLoadCount === 'number'
? opts.maxLoadCount ? opts.maxLoadCount
@ -2301,7 +2280,6 @@ const rowJanitor = (( ) => {
const obsolete = typeof opts.maxAge === 'number' const obsolete = typeof opts.maxAge === 'number'
? Date.now() - opts.maxAge * 60000 ? Date.now() - opts.maxAge * 60000
: 0; : 0;
const deadline = Date.now() + Math.ceil(timeRemaining);
let i = rowIndex; let i = rowIndex;
// TODO: below should not happen -- remove when confirmed. // TODO: below should not happen -- remove when confirmed.
@ -2322,7 +2300,7 @@ const rowJanitor = (( ) => {
while ( i < loggerEntries.length ) { while ( i < loggerEntries.length ) {
if ( i % 64 === 0 && Date.now() >= deadline ) { break; } if ( i % 64 === 0 && deadline.timeRemaining() === 0 ) { break; }
const entry = loggerEntries[i]; const entry = loggerEntries[i];
const tabId = entry.tabId || 0; const tabId = entry.tabId || 0;
@ -2391,18 +2369,15 @@ const rowJanitor = (( ) => {
rowFilterer.filterAll(); rowFilterer.filterAll();
}; };
const discardAsync = function() { const discardAsync = function(deadline) {
setTimeout( if ( deadline ) {
( ) => { discard(deadline);
self.requestIdleCallback(deadline => { }
discard(deadline.timeRemaining()); janitorTimer.onidle(1889);
discardAsync();
});
},
1889
);
}; };
const janitorTimer = vAPI.defer.create(discardAsync);
// Clear voided entries from the logger's visible content. // Clear voided entries from the logger's visible content.
// //
// Voided entries should be visible only from the "All" option of the // Voided entries should be visible only from the "All" option of the
@ -3030,15 +3005,14 @@ dom.on(window, 'hashchange', pageSelectorFromURLHash);
// to the window geometry pontentially not settling fast enough. // to the window geometry pontentially not settling fast enough.
if ( self.location.search.includes('popup=1') ) { if ( self.location.search.includes('popup=1') ) {
dom.on(window, 'load', ( ) => { dom.on(window, 'load', ( ) => {
setTimeout( vAPI.defer.once(2000).then(( ) => {
( ) => { popupLoggerBox = {
popupLoggerBox = { x: self.screenX,
x: self.screenX, y: self.screenY,
y: self.screenY, w: self.outerWidth,
w: self.outerWidth, h: self.outerHeight,
h: self.outerHeight, };
}; });
}, 2000);
}, { once: true }); }, { once: true });
} }

View File

@ -27,21 +27,21 @@ let buffer = null;
let lastReadTime = 0; let lastReadTime = 0;
let writePtr = 0; let writePtr = 0;
// After 30 seconds without being read, a buffer will be considered // After 30 seconds without being read, the logger buffer will be considered
// unused, and thus removed from memory. // unused, and thus disabled.
const logBufferObsoleteAfter = 30 * 1000; const logBufferObsoleteAfter = 30 * 1000;
const janitor = ( ) => { const janitorTimer = vAPI.defer.create(( ) => {
if ( buffer === null ) { return; } if ( buffer === null ) { return; }
if ( lastReadTime >= (Date.now() - logBufferObsoleteAfter) ) { if ( lastReadTime >= (Date.now() - logBufferObsoleteAfter) ) {
return vAPI.setTimeout(janitor, logBufferObsoleteAfter); return janitorTimer.on(logBufferObsoleteAfter);
} }
logger.enabled = false; logger.enabled = false;
buffer = null; buffer = null;
writePtr = 0; writePtr = 0;
logger.ownerId = undefined; logger.ownerId = undefined;
vAPI.messaging.broadcast({ what: 'loggerDisabled' }); vAPI.messaging.broadcast({ what: 'loggerDisabled' });
}; });
const boxEntry = function(details) { const boxEntry = function(details) {
if ( details.tstamp === undefined ) { if ( details.tstamp === undefined ) {
@ -68,7 +68,7 @@ const logger = {
if ( buffer === null ) { if ( buffer === null ) {
this.enabled = true; this.enabled = true;
buffer = []; buffer = [];
vAPI.setTimeout(janitor, logBufferObsoleteAfter); janitorTimer.on(logBufferObsoleteAfter);
} }
const out = buffer.slice(0, writePtr); const out = buffer.slice(0, writePtr);
writePtr = 0; writePtr = 0;

View File

@ -42,7 +42,6 @@ let lz4CodecInstance;
let pendingInitialization; let pendingInitialization;
let textEncoder, textDecoder; let textEncoder, textDecoder;
let ttlCount = 0; let ttlCount = 0;
let ttlTimer;
let ttlDelay = 60000; let ttlDelay = 60000;
const init = function() { const init = function() {
@ -84,18 +83,16 @@ const destroy = function() {
lz4CodecInstance = undefined; lz4CodecInstance = undefined;
textEncoder = textDecoder = undefined; textEncoder = textDecoder = undefined;
ttlCount = 0; ttlCount = 0;
ttlTimer = undefined;
}; };
const ttlTimer = vAPI.defer.create(destroy);
const ttlManage = function(count) { const ttlManage = function(count) {
if ( ttlTimer !== undefined ) { ttlTimer.off();
clearTimeout(ttlTimer);
ttlTimer = undefined;
}
ttlCount += count; ttlCount += count;
if ( ttlCount > 0 ) { return; } if ( ttlCount > 0 ) { return; }
if ( lz4CodecInstance === null ) { return; } if ( lz4CodecInstance === null ) { return; }
ttlTimer = vAPI.setTimeout(destroy, ttlDelay); ttlTimer.on(ttlDelay);
}; };
const encodeValue = function(dataIn) { const encodeValue = function(dataIn) {

View File

@ -56,6 +56,9 @@ To create a log of net requests
const NetFilteringResultCache = class { const NetFilteringResultCache = class {
constructor() { constructor() {
this.pruneTimer = vAPI.defer.create(( ) => {
this.prune();
});
this.init(); this.init();
} }
@ -63,7 +66,6 @@ const NetFilteringResultCache = class {
this.blocked = new Map(); this.blocked = new Map();
this.results = new Map(); this.results = new Map();
this.hash = 0; this.hash = 0;
this.timer = undefined;
return this; return this;
} }
@ -111,10 +113,7 @@ const NetFilteringResultCache = class {
this.blocked.clear(); this.blocked.clear();
this.results.clear(); this.results.clear();
this.hash = 0; this.hash = 0;
if ( this.timer !== undefined ) { this.pruneTimer.off();
clearTimeout(this.timer);
this.timer = undefined;
}
} }
prune() { prune() {
@ -136,14 +135,7 @@ const NetFilteringResultCache = class {
} }
pruneAsync() { pruneAsync() {
if ( this.timer !== undefined ) { return; } this.pruneTimer.on(this.shelfLife);
this.timer = vAPI.setTimeout(
( ) => {
this.timer = undefined;
this.prune();
},
this.shelfLife
);
} }
lookupResult(fctxt) { lookupResult(fctxt) {
@ -353,12 +345,17 @@ const PageStore = class {
constructor(tabId, details) { constructor(tabId, details) {
this.extraData = new Map(); this.extraData = new Map();
this.journal = []; this.journal = [];
this.journalTimer = undefined;
this.journalLastCommitted = this.journalLastUncommitted = -1; this.journalLastCommitted = this.journalLastUncommitted = -1;
this.journalLastUncommittedOrigin = undefined; this.journalLastUncommittedOrigin = undefined;
this.netFilteringCache = NetFilteringResultCache.factory(); this.netFilteringCache = NetFilteringResultCache.factory();
this.hostnameDetailsMap = new HostnameDetailsMap(); this.hostnameDetailsMap = new HostnameDetailsMap();
this.counts = new CountDetails(); this.counts = new CountDetails();
this.journalTimer = vAPI.defer.create(( ) => {
this.journalProcess();
});
this.largeMediaTimer = vAPI.defer.create(( ) => {
this.injectLargeMediaElementScriptlet();
});
this.init(tabId, details); this.init(tabId, details);
} }
@ -398,7 +395,6 @@ const PageStore = class {
this.remoteFontCount = 0; this.remoteFontCount = 0;
this.popupBlockedCount = 0; this.popupBlockedCount = 0;
this.largeMediaCount = 0; this.largeMediaCount = 0;
this.largeMediaTimer = null;
this.allowLargeMediaElementsRegex = undefined; this.allowLargeMediaElementsRegex = undefined;
this.extraData.clear(); this.extraData.clear();
@ -441,10 +437,7 @@ const PageStore = class {
} }
// A new page is completely reloaded from scratch, reset all. // A new page is completely reloaded from scratch, reset all.
if ( this.largeMediaTimer !== null ) { this.largeMediaTimer.off();
clearTimeout(this.largeMediaTimer);
this.largeMediaTimer = null;
}
this.disposeFrameStores(); this.disposeFrameStores();
this.init(this.tabId, details); this.init(this.tabId, details);
return this; return this;
@ -458,15 +451,9 @@ const PageStore = class {
this.netFilteringCache.empty(); this.netFilteringCache.empty();
this.allowLargeMediaElementsUntil = Date.now(); this.allowLargeMediaElementsUntil = Date.now();
this.allowLargeMediaElementsRegex = undefined; this.allowLargeMediaElementsRegex = undefined;
if ( this.largeMediaTimer !== null ) { this.largeMediaTimer.off();
clearTimeout(this.largeMediaTimer);
this.largeMediaTimer = null;
}
this.disposeFrameStores(); this.disposeFrameStores();
if ( this.journalTimer !== undefined ) { this.journalTimer.off();
clearTimeout(this.journalTimer);
this.journalTimer = undefined;
}
this.journal = []; this.journal = [];
this.journalLastUncommittedOrigin = undefined; this.journalLastUncommittedOrigin = undefined;
this.journalLastCommitted = this.journalLastUncommitted = -1; this.journalLastCommitted = this.journalLastUncommitted = -1;
@ -668,11 +655,7 @@ const PageStore = class {
const hostname = fctxt.getHostname(); const hostname = fctxt.getHostname();
if ( hostname === '' ) { return; } if ( hostname === '' ) { return; }
this.journal.push(hostname, result, fctxt.itype); this.journal.push(hostname, result, fctxt.itype);
if ( this.journalTimer !== undefined ) { return; } this.journalTimer.on(µb.hiddenSettings.requestJournalProcessPeriod);
this.journalTimer = vAPI.setTimeout(
( ) => { this.journalProcess(true); },
µb.hiddenSettings.requestJournalProcessPeriod
);
} }
journalAddRootFrame(type, url) { journalAddRootFrame(type, url) {
@ -695,18 +678,11 @@ const PageStore = class {
this.journalLastUncommittedOrigin = newOrigin; this.journalLastUncommittedOrigin = newOrigin;
} }
} }
if ( this.journalTimer !== undefined ) { this.journalTimer.offon(µb.hiddenSettings.requestJournalProcessPeriod);
clearTimeout(this.journalTimer);
}
this.journalTimer = vAPI.setTimeout(
( ) => { this.journalProcess(true); },
µb.hiddenSettings.requestJournalProcessPeriod
);
} }
journalProcess(fromTimer = false) { journalProcess() {
if ( fromTimer === false ) { clearTimeout(this.journalTimer); } this.journalTimer.off();
this.journalTimer = undefined;
const journal = this.journal; const journal = this.journal;
const pivot = Math.max(0, this.journalLastCommitted); const pivot = Math.max(0, this.journalLastCommitted);
@ -1058,12 +1034,7 @@ const PageStore = class {
} }
this.largeMediaCount += 1; this.largeMediaCount += 1;
if ( this.largeMediaTimer === null ) { this.largeMediaTimer.on(500);
this.largeMediaTimer = vAPI.setTimeout(( ) => {
this.largeMediaTimer = null;
this.injectLargeMediaElementScriptlet();
}, 500);
}
if ( logger.enabled ) { if ( logger.enabled ) {
fctxt.filter = sessionSwitches.toLogData(); fctxt.filter = sessionSwitches.toLogData();

View File

@ -1376,29 +1376,23 @@ const toggleHostnameSwitch = async function(ev) {
// it and thus having to push it all the time unconditionally. // it and thus having to push it all the time unconditionally.
const pollForContentChange = (( ) => { const pollForContentChange = (( ) => {
let pollTimer;
const pollCallback = async function() { const pollCallback = async function() {
pollTimer = undefined;
const response = await messaging.send('popupPanel', { const response = await messaging.send('popupPanel', {
what: 'hasPopupContentChanged', what: 'hasPopupContentChanged',
tabId: popupData.tabId, tabId: popupData.tabId,
contentLastModified: popupData.contentLastModified, contentLastModified: popupData.contentLastModified,
}); });
queryCallback(response);
};
const queryCallback = function(response) {
if ( response ) { if ( response ) {
getPopupData(popupData.tabId); await getPopupData(popupData.tabId);
return; return;
} }
poll(); poll();
}; };
const pollTimer = vAPI.defer.create(pollCallback);
const poll = function() { const poll = function() {
if ( pollTimer !== undefined ) { return; } pollTimer.on(1500);
pollTimer = vAPI.setTimeout(pollCallback, 1500);
}; };
return poll; return poll;

View File

@ -36,11 +36,9 @@ import {
/******************************************************************************/ /******************************************************************************/
const workerTTL = 5 * 60 * 1000;
const pendingResponses = new Map(); const pendingResponses = new Map();
let worker = null; let worker = null;
let workerTTLTimer;
let needLists = true; let needLists = true;
let messageId = 1; let messageId = 1;
@ -52,10 +50,7 @@ const onWorkerMessage = function(e) {
}; };
const stopWorker = function() { const stopWorker = function() {
if ( workerTTLTimer !== undefined ) { stopWorker.off();
clearTimeout(workerTTLTimer);
workerTTLTimer = undefined;
}
if ( worker === null ) { return; } if ( worker === null ) { return; }
worker.terminate(); worker.terminate();
worker = null; worker = null;
@ -66,6 +61,9 @@ const stopWorker = function() {
pendingResponses.clear(); pendingResponses.clear();
}; };
const workerTTLTimer = vAPI.defer.create(stopWorker);
const workerTTL = { min: 5 };
const initWorker = function() { const initWorker = function() {
if ( worker === null ) { if ( worker === null ) {
worker = new Worker('js/reverselookup-worker.js'); worker = new Worker('js/reverselookup-worker.js');
@ -73,10 +71,7 @@ const initWorker = function() {
} }
// The worker will be shutdown after n minutes without being used. // The worker will be shutdown after n minutes without being used.
if ( workerTTLTimer !== undefined ) { workerTTLTimer.offon(workerTTL);
clearTimeout(workerTTLTimer);
}
workerTTLTimer = vAPI.setTimeout(stopWorker, workerTTL);
if ( needLists === false ) { if ( needLists === false ) {
return Promise.resolve(); return Promise.resolve();

View File

@ -98,23 +98,26 @@ import {
/******************************************************************************/ /******************************************************************************/
µb.saveLocalSettings = (( ) => { {
const saveAfter = 4 * 60 * 1000; let localSettingsLastSaved = Date.now();
const onTimeout = ( ) => { const shouldSave = ( ) => {
if ( µb.localSettingsLastModified > µb.localSettingsLastSaved ) { if ( µb.localSettingsLastModified > localSettingsLastSaved ) {
µb.saveLocalSettings(); µb.saveLocalSettings();
} }
vAPI.setTimeout(onTimeout, saveAfter); saveTimer.on(saveDelay);
}; };
vAPI.setTimeout(onTimeout, saveAfter); const saveTimer = vAPI.defer.create(shouldSave);
const saveDelay = { min: 4 };
return function() { saveTimer.on(saveDelay);
this.localSettingsLastSaved = Date.now();
µb.saveLocalSettings = function() {
localSettingsLastSaved = Date.now();
return vAPI.storage.set(this.localSettings); return vAPI.storage.set(this.localSettings);
}; };
})(); }
/******************************************************************************/ /******************************************************************************/
@ -1445,15 +1448,17 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
/******************************************************************************/ /******************************************************************************/
{ {
let timer, next = 0; let next = 0;
let lastEmergencyUpdate = 0; let lastEmergencyUpdate = 0;
µb.scheduleAssetUpdater = async function(updateDelay) { const launchTimer = vAPI.defer.create(fetchDelay => {
next = 0;
io.updateStart({ delay: fetchDelay, auto: true });
});
µb.scheduleAssetUpdater = async function(updateDelay) {
launchTimer.off();
if ( timer ) {
clearTimeout(timer);
timer = undefined;
}
if ( updateDelay === 0 ) { if ( updateDelay === 0 ) {
next = 0; next = 0;
return; return;
@ -1499,11 +1504,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
? 2000 ? 2000
: this.hiddenSettings.autoUpdateAssetFetchPeriod * 1000 || 60000; : this.hiddenSettings.autoUpdateAssetFetchPeriod * 1000 || 60000;
timer = vAPI.setTimeout(( ) => { launchTimer.on(updateDelay, fetchDelay);
timer = undefined;
next = 0;
io.updateStart({ delay: fetchDelay, auto: true });
}, updateDelay);
}; };
} }

View File

@ -515,25 +515,19 @@ housekeep itself.
? µb.maybeGoodPopup.url ? µb.maybeGoodPopup.url
: '' : ''
}; };
this.selfDestructionTimer = null; this.selfDestructionTimer = vAPI.defer.create(( ) => {
this.destroy();
});
this.launchSelfDestruction(); this.launchSelfDestruction();
} }
destroy() { destroy() {
if ( this.selfDestructionTimer !== null ) { this.selfDestructionTimer.off();
clearTimeout(this.selfDestructionTimer);
}
popupCandidates.delete(this.targetTabId); popupCandidates.delete(this.targetTabId);
} }
launchSelfDestruction() { launchSelfDestruction() {
if ( this.selfDestructionTimer !== null ) { this.selfDestructionTimer.offon(10000);
clearTimeout(this.selfDestructionTimer);
}
this.selfDestructionTimer = vAPI.setTimeout(
( ) => this.destroy(),
10000
);
} }
}; };
@ -618,8 +612,12 @@ housekeep itself.
this.origin = this.origin =
this.rootHostname = this.rootHostname =
this.rootDomain = ''; this.rootDomain = '';
this.commitTimer = null; this.commitTimer = vAPI.defer.create(( ) => {
this.gcTimer = null; this.onCommit();
});
this.gcTimer = vAPI.defer.create(( ) => {
this.onGC();
});
this.onGCBarrier = false; this.onGCBarrier = false;
this.netFiltering = true; this.netFiltering = true;
this.netFilteringReadTime = 0; this.netFilteringReadTime = 0;
@ -629,28 +627,20 @@ housekeep itself.
TabContext.prototype.destroy = function() { TabContext.prototype.destroy = function() {
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; } if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; }
if ( this.gcTimer !== null ) { this.gcTimer.off();
clearTimeout(this.gcTimer);
this.gcTimer = null;
}
tabContexts.delete(this.tabId); tabContexts.delete(this.tabId);
}; };
TabContext.prototype.onGC = async function() { TabContext.prototype.onGC = async function() {
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; } if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; }
// https://github.com/gorhill/uBlock/issues/1713
// For unknown reasons, Firefox's setTimeout() will sometimes
// causes the callback function to be called immediately, bypassing
// the main event loop. For now this should prevent uBO from
// crashing as a result of the bad setTimeout() behavior.
if ( this.onGCBarrier ) { return; } if ( this.onGCBarrier ) { return; }
this.onGCBarrier = true; this.onGCBarrier = true;
this.gcTimer = null; this.gcTimer.off();
const tab = await vAPI.tabs.get(this.tabId); const tab = await vAPI.tabs.get(this.tabId);
if ( tab instanceof Object === false || tab.discarded === true ) { if ( tab instanceof Object === false || tab.discarded === true ) {
this.destroy(); this.destroy();
} else { } else {
this.gcTimer = vAPI.setTimeout(( ) => this.onGC(), gcPeriod); this.gcTimer.on(gcPeriod);
} }
this.onGCBarrier = false; this.onGCBarrier = false;
}; };
@ -659,10 +649,8 @@ housekeep itself.
// Stack entries have to be committed to stick. Non-committed stack // Stack entries have to be committed to stick. Non-committed stack
// entries are removed after a set delay. // entries are removed after a set delay.
TabContext.prototype.onCommit = function() { TabContext.prototype.onCommit = function() {
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; }
return; this.commitTimer.off();
}
this.commitTimer = null;
// Remove uncommitted entries at the top of the stack. // Remove uncommitted entries at the top of the stack.
let i = this.stack.length; let i = this.stack.length;
while ( i-- ) { while ( i-- ) {
@ -687,7 +675,7 @@ housekeep itself.
// want to flush it. // want to flush it.
TabContext.prototype.autodestroy = function() { TabContext.prototype.autodestroy = function() {
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; } if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; }
this.gcTimer = vAPI.setTimeout(( ) => this.onGC(), gcPeriod); this.gcTimer.on(gcPeriod);
}; };
// Update just force all properties to be updated to match the most recent // Update just force all properties to be updated to match the most recent
@ -727,10 +715,7 @@ housekeep itself.
this.stack.push(new StackEntry(url)); this.stack.push(new StackEntry(url));
this.update(); this.update();
popupCandidateTest(this.tabId); popupCandidateTest(this.tabId);
if ( this.commitTimer !== null ) { this.commitTimer.offon(500);
clearTimeout(this.commitTimer);
}
this.commitTimer = vAPI.setTimeout(( ) => this.onCommit(), 500);
}; };
// This tells that the url is definitely the one to be associated with the // This tells that the url is definitely the one to be associated with the
@ -1156,7 +1141,6 @@ vAPI.tabs = new vAPI.Tabs();
// Stale page store entries janitor // Stale page store entries janitor
{ {
const pageStoreJanitorPeriod = 15 * 60 * 1000;
let pageStoreJanitorSampleAt = 0; let pageStoreJanitorSampleAt = 0;
let pageStoreJanitorSampleSize = 10; let pageStoreJanitorSampleSize = 10;
@ -1182,10 +1166,13 @@ vAPI.tabs = new vAPI.Tabs();
} }
pageStoreJanitorSampleAt = n; pageStoreJanitorSampleAt = n;
vAPI.setTimeout(pageStoreJanitor, pageStoreJanitorPeriod); pageStoreJanitorTimer.on(pageStoreJanitorPeriod);
}; };
vAPI.setTimeout(pageStoreJanitor, pageStoreJanitorPeriod); const pageStoreJanitorTimer = vAPI.defer.create(pageStoreJanitor);
const pageStoreJanitorPeriod = { min: 15 };
pageStoreJanitorTimer.on(pageStoreJanitorPeriod);
} }
/******************************************************************************/ /******************************************************************************/

View File

@ -439,23 +439,23 @@ const onBeforeBehindTheSceneRequest = function(fctxt) {
// request. // request.
{ {
const pageStores = new Set();
let hostname = ''; let hostname = '';
let pageStores = new Set();
let pageStoresToken = 0; let pageStoresToken = 0;
let gcTimer;
const reset = function() { const reset = function() {
hostname = ''; hostname = '';
pageStores = new Set(); pageStores.clear();
pageStoresToken = 0; pageStoresToken = 0;
}; };
const gc = ( ) => { const gc = ( ) => {
gcTimer = undefined;
if ( pageStoresToken !== µb.pageStoresToken ) { return reset(); } if ( pageStoresToken !== µb.pageStoresToken ) { return reset(); }
gcTimer = vAPI.setTimeout(gc, 30011); gcTimer.on(30011);
}; };
const gcTimer = vAPI.defer.create(gc);
onBeforeBehindTheSceneRequest.journalAddRequest = (fctxt, result) => { onBeforeBehindTheSceneRequest.journalAddRequest = (fctxt, result) => {
const docHostname = fctxt.getDocHostname(); const docHostname = fctxt.getDocHostname();
if ( if (
@ -463,16 +463,13 @@ const onBeforeBehindTheSceneRequest = function(fctxt) {
pageStoresToken !== µb.pageStoresToken pageStoresToken !== µb.pageStoresToken
) { ) {
hostname = docHostname; hostname = docHostname;
pageStores = new Set(); pageStores.clear();
for ( const pageStore of µb.pageStores.values() ) { for ( const pageStore of µb.pageStores.values() ) {
if ( pageStore.tabHostname !== docHostname ) { continue; } if ( pageStore.tabHostname !== docHostname ) { continue; }
pageStores.add(pageStore); pageStores.add(pageStore);
} }
pageStoresToken = µb.pageStoresToken; pageStoresToken = µb.pageStoresToken;
if ( gcTimer !== undefined ) { gcTimer.offon(30011);
clearTimeout(gcTimer);
}
gcTimer = vAPI.setTimeout(gc, 30011);
} }
for ( const pageStore of pageStores ) { for ( const pageStore of pageStores ) {
pageStore.journalAddRequest(fctxt, result); pageStore.journalAddRequest(fctxt, result);
@ -1057,7 +1054,9 @@ const headerValueFromName = function(headerName, headers) {
const strictBlockBypasser = { const strictBlockBypasser = {
hostnameToDeadlineMap: new Map(), hostnameToDeadlineMap: new Map(),
cleanupTimer: undefined, cleanupTimer: vAPI.defer.create(( ) => {
strictBlockBypasser.cleanup();
}),
cleanup: function() { cleanup: function() {
for ( const [ hostname, deadline ] of this.hostnameToDeadlineMap ) { for ( const [ hostname, deadline ] of this.hostnameToDeadlineMap ) {
@ -1067,35 +1066,23 @@ const strictBlockBypasser = {
} }
}, },
revokeTime: function() {
return Date.now() + µb.hiddenSettings.strictBlockingBypassDuration * 1000;
},
bypass: function(hostname) { bypass: function(hostname) {
if ( typeof hostname !== 'string' || hostname === '' ) { return; } if ( typeof hostname !== 'string' || hostname === '' ) { return; }
this.hostnameToDeadlineMap.set( this.hostnameToDeadlineMap.set(hostname, this.revokeTime());
hostname,
Date.now() + µb.hiddenSettings.strictBlockingBypassDuration * 1000
);
}, },
isBypassed: function(hostname) { isBypassed: function(hostname) {
if ( this.hostnameToDeadlineMap.size === 0 ) { return false; } if ( this.hostnameToDeadlineMap.size === 0 ) { return false; }
let bypassDuration = this.cleanupTimer.on({ sec: µb.hiddenSettings.strictBlockingBypassDuration + 10 });
µb.hiddenSettings.strictBlockingBypassDuration * 1000;
if ( this.cleanupTimer === undefined ) {
this.cleanupTimer = vAPI.setTimeout(
( ) => {
this.cleanupTimer = undefined;
this.cleanup();
},
bypassDuration + 10000
);
}
for (;;) { for (;;) {
const deadline = this.hostnameToDeadlineMap.get(hostname); const deadline = this.hostnameToDeadlineMap.get(hostname);
if ( deadline !== undefined ) { if ( deadline !== undefined ) {
if ( deadline > Date.now() ) { if ( deadline > Date.now() ) {
this.hostnameToDeadlineMap.set( this.hostnameToDeadlineMap.set(hostname, this.revokeTime());
hostname,
Date.now() + bypassDuration
);
return true; return true;
} }
this.hostnameToDeadlineMap.delete(hostname); this.hostnameToDeadlineMap.delete(hostname);