PERF: avoid traversing DOM in loadScript

Once a script is loaded operation should be very fast.

This optimisation avoids a DOM traverse and call to getURL on
every invocation.
This commit is contained in:
Sam Saffron
2020-05-25 18:19:47 +10:00
parent 505122bb45
commit 48fb354bce

View File

@@ -45,34 +45,40 @@ export default function loadScript(url, opts) {
opts = opts || {}; opts = opts || {};
if (_loaded[url]) {
return Promise.resolve();
}
// Scripts should always load from CDN // Scripts should always load from CDN
// CSS is type text, to accept it from a CDN we would need to handle CORS // CSS is type text, to accept it from a CDN we would need to handle CORS
url = opts.css ? Discourse.getURL(url) : Discourse.getURLWithCDN(url); const fullUrl = opts.css
? Discourse.getURL(url)
: Discourse.getURLWithCDN(url);
$("script").each((i, tag) => { $("script").each((i, tag) => {
const src = tag.getAttribute("src"); const src = tag.getAttribute("src");
if (src && src !== url && !_loading[src]) { if (src && src !== fullUrl && !_loading[src]) {
_loaded[src] = true; _loaded[src] = true;
} }
}); });
return new Promise(function(resolve) { return new Promise(function(resolve) {
// If we already loaded this url // If we already loaded this url
if (_loaded[url]) { if (_loaded[fullUrl]) {
return resolve(); return resolve();
} }
if (_loading[url]) { if (_loading[fullUrl]) {
return _loading[url].then(resolve); return _loading[fullUrl].then(resolve);
} }
let done; let done;
_loading[url] = new Promise(function(_done) { _loading[fullUrl] = new Promise(function(_done) {
done = _done; done = _done;
}); });
_loading[url].then(function() { _loading[fullUrl].then(function() {
delete _loading[url]; delete _loading[fullUrl];
}); });
const cb = function(data) { const cb = function(data) {
@@ -82,17 +88,18 @@ export default function loadScript(url, opts) {
done(); done();
resolve(); resolve();
_loaded[url] = true; _loaded[url] = true;
_loaded[fullUrl] = true;
}; };
if (opts.css) { if (opts.css) {
ajax({ ajax({
url: url, url: fullUrl,
dataType: "text", dataType: "text",
cache: true cache: true
}).then(cb); }).then(cb);
} else { } else {
// Always load JavaScript with script tag to avoid Content Security Policy inline violations // Always load JavaScript with script tag to avoid Content Security Policy inline violations
loadWithTag(url, cb); loadWithTag(fullUrl, cb);
} }
}); });
} }