Skip to content

Instantly share code, notes, and snippets.

@aganglada
Created February 24, 2017 11:00
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aganglada/64381cc577db5c2a8cd8957179cbdade to your computer and use it in GitHub Desktop.
Save aganglada/64381cc577db5c2a8cd8957179cbdade to your computer and use it in GitHub Desktop.
Script Cache Promise based
let counter = 0;
let scriptMap = new Map();
export const ScriptCache = (function(global) {
return function ScriptCache (scripts) {
const Cache = {};
Cache._onLoad = function(key) {
return (cb) => {
let stored = scriptMap.get(key);
if (stored) {
stored.promise.then(() => {
stored.error ? cb(stored.error) : cb(null, stored)
})
} else {
console.warn('No script cached');
}
}
};
Cache._scriptTag = (key, src) => {
if (!scriptMap.has(key)) {
let tag = document.createElement('script');
let promise = new Promise((resolve, reject) => {
let resolved = false,
errored = false,
body = document.getElementsByTagName('body')[0];
tag.type = 'text/javascript';
tag.async = true;
tag.defer = true;
const cbName = `loaderCB${counter++}${Date.now()}`;
let cb;
const handleResult = (state) => {
return (evt) => {
let stored = scriptMap.get(key);
if (state === 'loaded') {
stored.resolved = true;
resolve(src);
} else if (state === 'error') {
stored.errored = true;
reject(evt)
}
cleanup();
}
};
const cleanup = () => {
if (global[cbName] && typeof global[cbName] === 'function') {
global[cbName] = null;
}
};
tag.onload = handleResult('loaded');
tag.onerror = handleResult('error');
tag.onreadystatechange = () => {
handleResult(tag.readyState)
};
if (src.match(/callback=CALLBACK_NAME/)) {
src = src.replace(/(callback=)[^\&]+/, `$1${cbName}`)
cb = window[cbName] = tag.onload;
} else {
tag.addEventListener('load', tag.onload)
}
tag.addEventListener('error', tag.onerror);
tag.src = src;
body.appendChild(tag);
return tag;
});
let initialState = {
loaded: false,
error: false,
promise,
tag
};
scriptMap.set(key, initialState);
}
return scriptMap.get(key);
};
Object.keys(scripts).forEach(function(key) {
const script = scripts[key];
Cache[key] = {
tag: Cache._scriptTag(key, script),
onLoad: Cache._onLoad(key)
};
});
return Cache;
};
})(window);
export default ScriptCache;
@aganglada
Copy link
Author

aganglada commented Feb 24, 2017

Example of use:

import scriptCache form './script-cache';

const cache = scriptCache({
   google: 'https://maps.googleapis.com/maps/api/js?v=3&libraries=places'
});

cache.google.onLoad(() => {
   // ...here you can use google.maps...
})

@AntoniusGolly
Copy link

+1 for presenting this just-one-purpose class!
+1 for example usage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment