promisify DB access

This commit is contained in:
tophf 2017-04-26 00:48:27 +03:00
parent 02fd4f1abe
commit acc4d83b9d
4 changed files with 149 additions and 149 deletions

View File

@ -1,4 +1,4 @@
/* global getDatabase, getStyles, saveStyle */ /* global dbExec, getStyles, saveStyle */
'use strict'; 'use strict';
// eslint-disable-next-line no-var // eslint-disable-next-line no-var
@ -6,7 +6,7 @@ var browserCommands, contextMenus;
// ************************************************************************* // *************************************************************************
// preload the DB and report errors // preload the DB and report errors
getDatabase(() => {}, (...args) => { dbExec().catch((...args) => {
args.forEach(arg => 'message' in arg && console.error(arg.message)); args.forEach(arg => 'message' in arg && console.error(arg.message));
}); });
@ -183,7 +183,7 @@ prefs.subscribe((id, checked) => {
// ************************************************************************* // *************************************************************************
function webNavigationListener(method, {url, tabId, frameId}) { function webNavigationListener(method, {url, tabId, frameId}) {
getStyles({matchUrl: url, enabled: true, asHash: true}, styles => { getStyles({matchUrl: url, enabled: true, asHash: true}).then(styles => {
if (method && !url.startsWith('chrome:') && tabId >= 0) { if (method && !url.startsWith('chrome:') && tabId >= 0) {
chrome.tabs.sendMessage(tabId, { chrome.tabs.sendMessage(tabId, {
method, method,
@ -209,9 +209,9 @@ function updateIcon(tab, styles) {
stylesReceived(styles); stylesReceived(styles);
return; return;
} }
getTabRealURL(tab).then(url => getTabRealURL(tab)
getStyles({matchUrl: url, enabled: true, asHash: true}, .then(url => getStyles({matchUrl: url, enabled: true, asHash: true}))
stylesReceived)); .then(stylesReceived);
function stylesReceived(styles) { function stylesReceived(styles) {
let numStyles = styles.length; let numStyles = styles.length;
@ -255,7 +255,7 @@ function onRuntimeMessage(request, sender, sendResponse) {
switch (request.method) { switch (request.method) {
case 'getStyles': case 'getStyles':
getStyles(request, sendResponse); getStyles(request).then(sendResponse);
return KEEP_CHANNEL_OPEN; return KEEP_CHANNEL_OPEN;
case 'saveStyle': case 'saveStyle':
@ -263,9 +263,9 @@ function onRuntimeMessage(request, sender, sendResponse) {
return KEEP_CHANNEL_OPEN; return KEEP_CHANNEL_OPEN;
case 'healthCheck': case 'healthCheck':
getDatabase( dbExec()
() => sendResponse(true), .then(() => sendResponse(true))
() => sendResponse(false)); .catch(() => sendResponse(false));
return KEEP_CHANNEL_OPEN; return KEEP_CHANNEL_OPEN;
case 'download': case 'download':

View File

@ -268,13 +268,13 @@ function sessionStorageHash(name) {
} }
function onBackgroundReady() { function onBackgroundReady(...dataPassthru) {
return BG ? Promise.resolve() : new Promise(ping); return BG ? Promise.resolve(...dataPassthru) : new Promise(ping);
function ping(resolve) { function ping(resolve) {
chrome.runtime.sendMessage({method: 'healthCheck'}, health => { chrome.runtime.sendMessage({method: 'healthCheck'}, health => {
if (health !== undefined) { if (health !== undefined) {
BG = chrome.extension.getBackgroundPage(); BG = chrome.extension.getBackgroundPage();
resolve(); resolve(...dataPassthru);
} else { } else {
ping(resolve); ping(resolve);
} }
@ -285,20 +285,13 @@ function onBackgroundReady() {
// in case Chrome haven't yet loaded the bg page and displays our page like edit/manage // in case Chrome haven't yet loaded the bg page and displays our page like edit/manage
function getStylesSafe(options) { function getStylesSafe(options) {
return new Promise(resolve => { return onBackgroundReady(options).then(BG.getStyles);
if (BG) {
BG.getStyles(options, resolve);
} else {
onBackgroundReady().then(() =>
BG.getStyles(options, resolve));
}
});
} }
function saveStyleSafe(style) { function saveStyleSafe(style) {
return onBackgroundReady() return onBackgroundReady(BG.deepCopy(style))
.then(() => BG.saveStyle(BG.deepCopy(style))) .then(BG.saveStyle)
.then(savedStyle => { .then(savedStyle => {
if (style.notify === false) { if (style.notify === false) {
handleUpdate(savedStyle, style); handleUpdate(savedStyle, style);
@ -309,8 +302,8 @@ function saveStyleSafe(style) {
function deleteStyleSafe({id, notify = true} = {}) { function deleteStyleSafe({id, notify = true} = {}) {
return onBackgroundReady() return onBackgroundReady({id, notify})
.then(() => BG.deleteStyle({id, notify})) .then(BG.deleteStyle)
.then(() => { .then(() => {
if (!notify) { if (!notify) {
handleDelete(id); handleDelete(id);

View File

@ -43,58 +43,69 @@ var chromeLocal = {
}; };
function getDatabase(ready, error) { function dbExec(method, data) {
const dbOpenRequest = window.indexedDB.open('stylish', 2); return new Promise((resolve, reject) => {
dbOpenRequest.onsuccess = event => { Object.assign(indexedDB.open('stylish', 2), {
ready(event.target.result); onsuccess(event) {
}; const database = event.target.result;
dbOpenRequest.onerror = event => { if (!method) {
console.warn(event.target.errorCode); resolve(database);
if (error) { } else {
error(event); const transaction = database.transaction(['styles'], 'readwrite');
} const store = transaction.objectStore('styles');
}; Object.assign(store[method](data), {
dbOpenRequest.onupgradeneeded = event => { onsuccess: event => resolve(event, store, transaction, database),
if (event.oldVersion == 0) { onerror: reject,
event.target.result.createObjectStore('styles', { });
keyPath: 'id', }
autoIncrement: true, },
}); onerror(event) {
} console.warn(event.target.errorCode);
}; reject(event);
},
onupgradeneeded(event) {
if (event.oldVersion == 0) {
event.target.result.createObjectStore('styles', {
keyPath: 'id',
autoIncrement: true,
});
}
},
});
});
} }
function getStyles(options, callback) { function getStyles(options) {
if (cachedStyles.list) { if (cachedStyles.list) {
callback(filterStyles(options)); return Promise.resolve(filterStyles(options));
return;
} }
if (cachedStyles.mutex.inProgress) { if (cachedStyles.mutex.inProgress) {
cachedStyles.mutex.onDone.push({options, callback}); return new Promise(resolve => {
return; cachedStyles.mutex.onDone.push({options, resolve});
});
} }
cachedStyles.mutex.inProgress = true; cachedStyles.mutex.inProgress = true;
getDatabase(db => { return dbExec('getAll').then(event => {
const tx = db.transaction(['styles'], 'readonly'); cachedStyles.list = event.target.result || [];
const os = tx.objectStore('styles'); cachedStyles.byId.clear();
os.getAll().onsuccess = event => { const t0 = performance.now();
cachedStyles.list = event.target.result || []; let hasTimeToCompile = true;
cachedStyles.byId.clear(); for (const style of cachedStyles.list) {
for (const style of cachedStyles.list) { cachedStyles.byId.set(style.id, style);
cachedStyles.byId.set(style.id, style); if (hasTimeToCompile) {
compileStyleRegExps({style}); hasTimeToCompile = !compileStyleRegExps({style}) || performance.now() - t0 > 100;
} }
callback(filterStyles(options)); }
cachedStyles.mutex.inProgress = false; cachedStyles.mutex.inProgress = false;
for (const {options, callback} of cachedStyles.mutex.onDone) { for (const {options, resolve} of cachedStyles.mutex.onDone) {
callback(filterStyles(options)); resolve(filterStyles(options));
} }
cachedStyles.mutex.onDone = []; cachedStyles.mutex.onDone = [];
}; return filterStyles(options);
}, null); });
} }
@ -213,83 +224,81 @@ function filterStylesInternal({
function saveStyle(style) { function saveStyle(style) {
return new Promise(resolve => { const id = Number(style.id) >= 0 ? Number(style.id) : null;
getDatabase(db => { const reason = style.reason;
const tx = db.transaction(['styles'], 'readwrite'); const notify = style.notify !== false;
const os = tx.objectStore('styles'); delete style.method;
delete style.reason;
const id = style.id == '0' ? 0 : Number(style.id) || null; delete style.notify;
const reason = style.reason; if (!style.name) {
const notify = style.notify !== false; delete style.name;
delete style.method; }
delete style.reason; let existed, codeIsUpdated;
delete style.notify; if (id !== null) {
if (!style.name) { // Update or create
delete style.name; style.id = id;
} return dbExec('get', id).then((event, store) => {
let existed, codeIsUpdated; const oldStyle = event.target.result;
existed = Boolean(oldStyle);
if (id !== null) { codeIsUpdated = !existed || style.sections && !styleSectionsEqual(style, oldStyle);
// Update or create style = Object.assign({}, oldStyle, style);
style.id = id; return write(style, store);
os.get(id).onsuccess = eventGet => {
const oldStyle = eventGet.target.result;
existed = Boolean(oldStyle);
codeIsUpdated = !existed || style.sections && !styleSectionsEqual(style, oldStyle);
write(Object.assign({}, oldStyle, style));
};
} else {
// Create
delete style.id;
write(Object.assign({
// Set optional things if they're undefined
enabled: true,
updateUrl: null,
md5Url: null,
url: null,
originalMd5: null,
}, style));
}
function write(style) {
style.sections = normalizeStyleSections(style);
os.put(style).onsuccess = event => {
style.id = style.id || event.target.result;
invalidateCache(existed ? {updated: style} : {added: style});
compileStyleRegExps({style});
if (notify) {
notifyAllTabs({
method: existed ? 'styleUpdated' : 'styleAdded',
style, codeIsUpdated, reason,
});
}
if (reason == 'update') {
updateStyleDigest(style);
} else if (reason == 'import') {
chrome.storage.local.remove(DIGEST_KEY_PREFIX + style.id, ignoreChromeError);
}
resolve(style);
};
}
}); });
}); } else {
// Create
delete style.id;
style = Object.assign({
// Set optional things if they're undefined
enabled: true,
updateUrl: null,
md5Url: null,
url: null,
originalMd5: null,
}, style);
return write(style);
}
function write(style, store) {
style.sections = normalizeStyleSections(style);
if (store) {
return new Promise(resolve => {
store.put(style).onsuccess = event => resolve(done(event));
});
} else {
return dbExec('put', style).then(done);
}
}
function done(event) {
style.id = style.id || event.target.result;
invalidateCache(existed ? {updated: style} : {added: style});
compileStyleRegExps({style});
if (notify) {
notifyAllTabs({
method: existed ? 'styleUpdated' : 'styleAdded',
style, codeIsUpdated, reason,
});
}
if (reason == 'update') {
updateStyleDigest(style);
} else if (reason == 'import') {
chrome.storage.local.remove(DIGEST_KEY_PREFIX + style.id, ignoreChromeError);
}
return style;
}
} }
function deleteStyle({id, notify = true}) { function deleteStyle({id, notify = true}) {
id = Number(id);
chrome.storage.local.remove(DIGEST_KEY_PREFIX + id, ignoreChromeError); chrome.storage.local.remove(DIGEST_KEY_PREFIX + id, ignoreChromeError);
return new Promise(resolve => return dbExec('delete', id).then(() => {
getDatabase(db => { invalidateCache({deletedId: id});
const tx = db.transaction(['styles'], 'readwrite'); if (notify) {
const os = tx.objectStore('styles'); notifyAllTabs({method: 'styleDeleted', id});
os.delete(Number(id)).onsuccess = () => { }
invalidateCache({deletedId: id}); return id;
if (notify) { });
notifyAllTabs({method: 'styleDeleted', id});
}
resolve(id);
};
}));
} }
@ -448,11 +457,12 @@ function compileStyleRegExps({style, compileAll}) {
const rx = tryRegExp(anchored); const rx = tryRegExp(anchored);
cachedStyles.regexps.set(cacheKey, rx || false); cachedStyles.regexps.set(cacheKey, rx || false);
if (!compileAll && performance.now() - t0 > 100) { if (!compileAll && performance.now() - t0 > 100) {
return; return false;
} }
} }
} }
} }
return true;
} }

View File

@ -22,17 +22,14 @@ var updater = {
checkAllStyles({observer = () => {}, save = true, ignoreDigest} = {}) { checkAllStyles({observer = () => {}, save = true, ignoreDigest} = {}) {
updater.resetInterval(); updater.resetInterval();
return new Promise(resolve => { return getStyles({}).then(styles => {
getStyles({}, styles => { styles = styles.filter(style => style.updateUrl);
styles = styles.filter(style => style.updateUrl); observer(updater.COUNT, styles.length);
observer(updater.COUNT, styles.length); return Promise.all(
Promise.all(styles.map(style => styles.map(style =>
updater.checkStyle({style, observer, save, ignoreDigest}) updater.checkStyle({style, observer, save, ignoreDigest})));
)).then(() => { }).then(() => {
observer(updater.DONE); observer(updater.DONE);
resolve();
});
});
}); });
}, },