1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-07-05 11:37:01 +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.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 = {

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;
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.hintUpdateToken !== undefined ) {
const mode = cmEditor.getMode();
@ -73,15 +78,12 @@ let cachedUserFilters = '';
}
hintUpdateToken = response.hintUpdateToken;
}
vAPI.setTimeout(getHints, 2503);
timer.on(2503);
};
const getHints = function() {
vAPI.messaging.send('dashboard', {
what: 'getAutoCompleteDetails',
hintUpdateToken
}).then(responseHandler);
};
const timer = vAPI.defer.create(( ) => {
getHints();
});
getHints();
}
@ -306,8 +308,7 @@ dom.on('#userFiltersRevert', 'click', revertChanges);
// https://github.com/gorhill/uBlock/issues/3706
// Save/restore cursor position
{
const line =
await vAPI.localStorage.getItemAsync('myFiltersCursorPosition');
const line = await vAPI.localStorage.getItemAsync('myFiltersCursorPosition');
if ( typeof line === 'number' ) {
cmEditor.setCursor(line, 0);
}
@ -317,15 +318,14 @@ dom.on('#userFiltersRevert', 'click', revertChanges);
// Save/restore cursor position
{
let curline = 0;
let timer;
cmEditor.on('cursorActivity', ( ) => {
if ( timer !== undefined ) { return; }
if ( timer.ongoing() ) { return; }
if ( cmEditor.getCursor().line === curline ) { return; }
timer = vAPI.setTimeout(( ) => {
timer = undefined;
curline = cmEditor.getCursor().line;
vAPI.localStorage.setItem('myFiltersCursorPosition', curline);
}, 701);
timer.on(701);
});
const timer = vAPI.defer.create(( ) => {
curline = cmEditor.getCursor().line;
vAPI.localStorage.setItem('myFiltersCursorPosition', curline);
});
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -211,7 +211,7 @@ async function setURL(resourceURL) {
dom.attr(a, 'title', afterURL);
addPastURLs(afterURL);
// 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;
}
if ( queryTextFromSearchWidget(cm) === state.queryText ) { return; }
if ( state.queryTimer !== null ) {
clearTimeout(state.queryTimer);
}
state.queryTimer = setTimeout(
() => {
state.queryTimer = null;
findCommit(cm, 0);
},
350
);
state.queryTimer.offon(350);
};
const searchWidgetClickHandler = function(cm, ev) {
@ -141,7 +132,6 @@ import { i18n$ } from '../i18n.js';
this.panel = cm.addPanel(this.widget);
}
this.queryText = '';
this.queryTimer = null;
this.dirty = true;
this.lines = [];
cm.on('changes', (cm, changes) => {
@ -155,6 +145,9 @@ import { i18n$ } from '../i18n.js';
cm.on('cursorActivity', 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
@ -426,10 +419,7 @@ import { i18n$ } from '../i18n.js';
const findCommit = function(cm, dir) {
const state = getSearchState(cm);
if ( state.queryTimer !== null ) {
clearTimeout(state.queryTimer);
state.queryTimer = null;
}
state.queryTimer.off();
const queryText = queryTextFromSearchWidget(cm);
if ( queryText === state.queryText ) { return; }
state.queryText = queryText;

View File

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

View File

@ -225,10 +225,12 @@ const FilterContainer = function() {
this.reSimpleHighGeneric = /^(?:[a-z]*\[[^\]]+\]|\S+)$/;
this.selectorCache = new Map();
this.selectorCachePruneDelay = 10 * 60 * 1000; // 10 minutes
this.selectorCachePruneDelay = 10; // 10 minutes
this.selectorCacheCountMin = 40;
this.selectorCacheCountMax = 50;
this.selectorCacheTimer = null;
this.selectorCacheTimer = vAPI.defer.create(( ) => {
this.pruneSelectorCacheAsync();
});
// specific filters
this.specificFilters = new StaticExtFilteringHostnameDB(2);
@ -274,10 +276,7 @@ FilterContainer.prototype.reset = function() {
this.duplicateBuster = new Set();
this.selectorCache.clear();
if ( this.selectorCacheTimer !== null ) {
clearTimeout(this.selectorCacheTimer);
this.selectorCacheTimer = null;
}
this.selectorCacheTimer.off();
// hostname, entity-based filters
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) {
const hostname = details.hostname;
if ( typeof hostname !== 'string' || hostname === '' ) { return; }
@ -626,7 +613,7 @@ FilterContainer.prototype.addToSelectorCache = function(details) {
entry = SelectorCacheEntry.factory();
this.selectorCache.set(hostname, entry);
if ( this.selectorCache.size > this.selectorCacheCountMax ) {
this.triggerSelectorCachePruner();
this.selectorCacheTimer.on({ min: this.selectorCachePruneDelay });
}
}
entry.add(details);
@ -658,7 +645,6 @@ FilterContainer.prototype.removeFromSelectorCache = function(
/******************************************************************************/
FilterContainer.prototype.pruneSelectorCacheAsync = function() {
this.selectorCacheTimer = null;
if ( this.selectorCache.size <= this.selectorCacheCountMax ) { return; }
const cache = this.selectorCache;
const hostnames = Array.from(cache.keys())

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -36,11 +36,9 @@ import {
/******************************************************************************/
const workerTTL = 5 * 60 * 1000;
const pendingResponses = new Map();
let worker = null;
let workerTTLTimer;
let needLists = true;
let messageId = 1;
@ -52,10 +50,7 @@ const onWorkerMessage = function(e) {
};
const stopWorker = function() {
if ( workerTTLTimer !== undefined ) {
clearTimeout(workerTTLTimer);
workerTTLTimer = undefined;
}
stopWorker.off();
if ( worker === null ) { return; }
worker.terminate();
worker = null;
@ -66,6 +61,9 @@ const stopWorker = function() {
pendingResponses.clear();
};
const workerTTLTimer = vAPI.defer.create(stopWorker);
const workerTTL = { min: 5 };
const initWorker = function() {
if ( worker === null ) {
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.
if ( workerTTLTimer !== undefined ) {
clearTimeout(workerTTLTimer);
}
workerTTLTimer = vAPI.setTimeout(stopWorker, workerTTL);
workerTTLTimer.offon(workerTTL);
if ( needLists === false ) {
return Promise.resolve();

View File

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

View File

@ -515,25 +515,19 @@ housekeep itself.
? µb.maybeGoodPopup.url
: ''
};
this.selfDestructionTimer = null;
this.selfDestructionTimer = vAPI.defer.create(( ) => {
this.destroy();
});
this.launchSelfDestruction();
}
destroy() {
if ( this.selfDestructionTimer !== null ) {
clearTimeout(this.selfDestructionTimer);
}
this.selfDestructionTimer.off();
popupCandidates.delete(this.targetTabId);
}
launchSelfDestruction() {
if ( this.selfDestructionTimer !== null ) {
clearTimeout(this.selfDestructionTimer);
}
this.selfDestructionTimer = vAPI.setTimeout(
( ) => this.destroy(),
10000
);
this.selfDestructionTimer.offon(10000);
}
};
@ -618,8 +612,12 @@ housekeep itself.
this.origin =
this.rootHostname =
this.rootDomain = '';
this.commitTimer = null;
this.gcTimer = null;
this.commitTimer = vAPI.defer.create(( ) => {
this.onCommit();
});
this.gcTimer = vAPI.defer.create(( ) => {
this.onGC();
});
this.onGCBarrier = false;
this.netFiltering = true;
this.netFilteringReadTime = 0;
@ -629,28 +627,20 @@ housekeep itself.
TabContext.prototype.destroy = function() {
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; }
if ( this.gcTimer !== null ) {
clearTimeout(this.gcTimer);
this.gcTimer = null;
}
this.gcTimer.off();
tabContexts.delete(this.tabId);
};
TabContext.prototype.onGC = async function() {
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; }
this.onGCBarrier = true;
this.gcTimer = null;
this.gcTimer.off();
const tab = await vAPI.tabs.get(this.tabId);
if ( tab instanceof Object === false || tab.discarded === true ) {
this.destroy();
} else {
this.gcTimer = vAPI.setTimeout(( ) => this.onGC(), gcPeriod);
this.gcTimer.on(gcPeriod);
}
this.onGCBarrier = false;
};
@ -659,10 +649,8 @@ housekeep itself.
// Stack entries have to be committed to stick. Non-committed stack
// entries are removed after a set delay.
TabContext.prototype.onCommit = function() {
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
return;
}
this.commitTimer = null;
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; }
this.commitTimer.off();
// Remove uncommitted entries at the top of the stack.
let i = this.stack.length;
while ( i-- ) {
@ -687,7 +675,7 @@ housekeep itself.
// want to flush it.
TabContext.prototype.autodestroy = function() {
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
@ -727,10 +715,7 @@ housekeep itself.
this.stack.push(new StackEntry(url));
this.update();
popupCandidateTest(this.tabId);
if ( this.commitTimer !== null ) {
clearTimeout(this.commitTimer);
}
this.commitTimer = vAPI.setTimeout(( ) => this.onCommit(), 500);
this.commitTimer.offon(500);
};
// 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
{
const pageStoreJanitorPeriod = 15 * 60 * 1000;
let pageStoreJanitorSampleAt = 0;
let pageStoreJanitorSampleSize = 10;
@ -1182,10 +1166,13 @@ vAPI.tabs = new vAPI.Tabs();
}
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.
{
const pageStores = new Set();
let hostname = '';
let pageStores = new Set();
let pageStoresToken = 0;
let gcTimer;
const reset = function() {
hostname = '';
pageStores = new Set();
pageStores.clear();
pageStoresToken = 0;
};
const gc = ( ) => {
gcTimer = undefined;
if ( pageStoresToken !== µb.pageStoresToken ) { return reset(); }
gcTimer = vAPI.setTimeout(gc, 30011);
gcTimer.on(30011);
};
const gcTimer = vAPI.defer.create(gc);
onBeforeBehindTheSceneRequest.journalAddRequest = (fctxt, result) => {
const docHostname = fctxt.getDocHostname();
if (
@ -463,16 +463,13 @@ const onBeforeBehindTheSceneRequest = function(fctxt) {
pageStoresToken !== µb.pageStoresToken
) {
hostname = docHostname;
pageStores = new Set();
pageStores.clear();
for ( const pageStore of µb.pageStores.values() ) {
if ( pageStore.tabHostname !== docHostname ) { continue; }
pageStores.add(pageStore);
}
pageStoresToken = µb.pageStoresToken;
if ( gcTimer !== undefined ) {
clearTimeout(gcTimer);
}
gcTimer = vAPI.setTimeout(gc, 30011);
gcTimer.offon(30011);
}
for ( const pageStore of pageStores ) {
pageStore.journalAddRequest(fctxt, result);
@ -1057,7 +1054,9 @@ const headerValueFromName = function(headerName, headers) {
const strictBlockBypasser = {
hostnameToDeadlineMap: new Map(),
cleanupTimer: undefined,
cleanupTimer: vAPI.defer.create(( ) => {
strictBlockBypasser.cleanup();
}),
cleanup: function() {
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) {
if ( typeof hostname !== 'string' || hostname === '' ) { return; }
this.hostnameToDeadlineMap.set(
hostname,
Date.now() + µb.hiddenSettings.strictBlockingBypassDuration * 1000
);
this.hostnameToDeadlineMap.set(hostname, this.revokeTime());
},
isBypassed: function(hostname) {
if ( this.hostnameToDeadlineMap.size === 0 ) { return false; }
let bypassDuration =
µb.hiddenSettings.strictBlockingBypassDuration * 1000;
if ( this.cleanupTimer === undefined ) {
this.cleanupTimer = vAPI.setTimeout(
( ) => {
this.cleanupTimer = undefined;
this.cleanup();
},
bypassDuration + 10000
);
}
this.cleanupTimer.on({ sec: µb.hiddenSettings.strictBlockingBypassDuration + 10 });
for (;;) {
const deadline = this.hostnameToDeadlineMap.get(hostname);
if ( deadline !== undefined ) {
if ( deadline > Date.now() ) {
this.hostnameToDeadlineMap.set(
hostname,
Date.now() + bypassDuration
);
this.hostnameToDeadlineMap.set(hostname, this.revokeTime());
return true;
}
this.hostnameToDeadlineMap.delete(hostname);