LoadJS – A tiny async loader for modern browsers (710 bytes)
github.com
github.com
The drawback is a lower level API, and it is JS only. AFAIK loading CSS consistently cross browser is also a mine field if you want consistent error handling.
window._lload("http://example.com/foo.js", function (err) {
// `err` is script load error.
// otherwise, foo.js is loaded!
}/*, [optional context (`this`) variable here] */);Initially I was hesitant to add CSS support because handling load errors across browsers is very tricky but I think we came up with a good solution [1] that is tested down to IE9 [2].
[1] https://github.com/muicss/loadjs/blob/master/src/loadjs.js#L...
[2] https://github.com/muicss/loadjs/blob/master/test/tests.js#L...
The little-loader also has a section to detect JS loading and errors in IE8/9 (with a dedicated sub-section for the former), I didn't see anything like this in LoadJS... Did you find a terser workaround?
https://github.com/walmartlabs/little-loader/blob/42d233f360...
I'm somewhat familiar with little-loader because I've worked at making it smaller, but I'm not competent to judge whether its approach is necessarily the best...
loadjs('foobar').then(() => {
// foobar.js loaded
});
And then with the newer spec: await loadjs('foobar');
// foobar.js loaded
Such a pity that instead it uses a proprietary format.Edit: you could still add all other nice things without compromising the main thing, for example to add a "before":
loadjs.before(fnA).before(fnB).load('foobar').then(() => {}); (async () => {
// Code...
})()If you want the caller to "block", then it needs to await or .then() what it's calling.
https://github.com/tc39/proposal-dynamic-import
It basicly is what you are describing.
I think promises are a bad idea if loading JavaScript is on the critical path to rendering your page. Unless you have so much JavaScript that parsing takes a long time and you need to yield to the layout and composition engine...
I wrote my own bundle loader so that:
* cached JavaScript loads fast
* CSS is put into a JavaScript string and loaded as a JavaScript file so (1) success and error handling code is simplified and (2) because error handling for CSS is hard -- e.g mycss.js looks like insertCssStyle('.much {css: here}');
* Small images are compiled into the CSS as data. Fonts are loaded in the CSS as data (avoiding a couple of bugs).
* it starts loading in <head> (avoiding much delay).
* It inserts <script> elements (rather than use XHR and eval) so that stack traces are readable, and cross origin works well, and so the browser can multithread the loading and parsing.
* it requests scripts from a single cross origin cloudflare host (for speed and caching), but re-requests from the page's domain if that isn't working (for reliability).
* loading failures are logged to third party (for checking reliability).
* JavaScript bundles are wrapped in try/catch for logging, and they explicitly call a function too indicate the bundle loaded successfully (and to chain dependencies correctly for async loading).
It is hard to make a single page app load reliably, and to report failures correctly if it fails!
This may not be an issue with native ES6 Promises (since they rely on microtasks) but other implementations/polyfills may not be airtight (setTimeout-based ones aren't for sure, for example).
There is no obvious easy way to wait for an `async` script to finish loading and executing before running code that depends on it. For instance, how would I load the jQuery library asynchronously before running code that depends on jQuery?