onDOMscriptReady: notify all matching subscribers

This commit is contained in:
tophf 2017-12-08 21:55:08 +03:00
parent 32d89e58ea
commit 18b20d13be

View File

@ -51,21 +51,21 @@ var loadScript = (() => {
// natively declared <script> elements in html can't have onload= attribute // natively declared <script> elements in html can't have onload= attribute
// due to the default extension CSP that forbids inline code (and we don't want to relax it), // due to the default extension CSP that forbids inline code (and we don't want to relax it),
// so we're using MutationObserver to add onload event listener to the script element to be loaded // so we're using MutationObserver to add onload event listener to the script element to be loaded
window.onDOMscriptReady = (src, timeout = 1000) => { window.onDOMscriptReady = (srcSuffix, timeout = 1000) => {
if (!subscribers) { if (!subscribers) {
subscribers = new Map(); subscribers = new Map();
observer = new MutationObserver(observe); observer = new MutationObserver(observe);
observer.observe(document.head, {childList: true}); observer.observe(document.head, {childList: true});
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const listeners = subscribers.get(src); const listeners = subscribers.get(srcSuffix);
if (listeners) { if (listeners) {
listeners.push(resolve); listeners.push(resolve);
} else { } else {
subscribers.set(src, [resolve]); subscribers.set(srcSuffix, [resolve]);
} }
// no need to clear the timer since a resolved Promise won't reject anymore // a resolved Promise won't reject anymore
setTimeout(reject, timeout); setTimeout(() => emptyAfterCleanup(srcSuffix) + reject(), timeout);
}); });
}; };
@ -82,22 +82,33 @@ var loadScript = (() => {
} }
function getSubscribersForSrc(src) { function getSubscribersForSrc(src) {
for (const [subscribedSrc, listeners] of subscribers.entries()) { for (const [suffix, listeners] of subscribers.entries()) {
if (src.endsWith(subscribedSrc)) { if (src.endsWith(suffix)) {
return {subscribedSrc, listeners}; return {suffix, listeners};
} }
} }
} }
function notifySubscribers(event) { function notifySubscribers(event) {
this.removeEventListener('load', notifySubscribers); this.removeEventListener('load', notifySubscribers);
const {subscribedSrc, listeners = []} = getSubscribersForSrc(this.src) || {}; for (let data; (data = getSubscribersForSrc(this.src));) {
listeners.forEach(fn => fn(event)); data.listeners.forEach(fn => fn(event));
subscribers.delete(subscribedSrc); if (emptyAfterCleanup(data.suffix)) {
return;
}
}
}
function emptyAfterCleanup(suffix) {
if (!subscribers) {
return true;
}
subscribers.delete(suffix);
if (!subscribers.size) { if (!subscribers.size) {
observer.disconnect(); observer.disconnect();
observer = null; observer = null;
subscribers = null; subscribers = null;
return true;
} }
} }
})(); })();