There are several questions about this topic like the following one: Is the "async" attribute/property useful if a script is dynamically added to the DOM?
But all of these questions only focus on adding one script-tag to the DOM or only script-tags which do not depend on each other.
We use Three.js and their examples. Since Three.js is a sophisticated project which is around since a long time not the whole examples etc are build around ES modules. Therefore we load these example scripts dynamically by adding a script-tag. As mentioned in other questions adding a script-tag dynamically sets it to async. But you can override this behavior. This is quite nice for us because if we set the script to async:false
the execution order is preserved (which helps us keeping complexity low), what we do is basically the following (real-world code is much more involved but here I want to show the gist):
const attatch = (url, options = {}) => {
return new Promise((resolve, reject) => {
const element = document.createElement('script');
element.async = options.async || false;
element.src = url;
if (options.id) {
element.id = options.id;
}
element.onload = () => {
resolve();
};
element.onerror = (error) => {
reject(error);
};
starts.push(performance.now());
document.getElementById('container').appendChild(element);
});
};
Promise.all([
attatch('./three/lib/rthree.js'),
attatch('./three/lib/postprocessing/EffectComposer.js', {id: 'effect-composer-js'}),
attatch('./three/lib/postprocessing/RenderPass.js', {id: 'render-pass-js'}),
attatch('./three/lib/postprocessing/ShaderPass.js', {id: 'shader-pass-js'}),
attatch('./three/lib/shaders/LuminosityHighPassShader.js', {id: 'luminosity-high-pass-shader-js'}),
attatch('./three/lib/postprocessing/UnrealBloomPass.js', {id: 'unreal-bloom-pass-js'}),
attatch('./three/lib/postprocessing/OutlinePass.js', {id: 'outline-pass-js'})
]).then(() => {
// Run 3D content now
});
I did some benchmarking and I didn't discover any significant difference between setting async to false. But I'm not sure if I didn't miss anything. Especially because I also want the browser to construct the UI while loading the scripts and then start the Three.js scene if everything is ready. Since it's not that easy to benchmark this change in our real world app I created an example project. Since I found no real difference it makes me wonder if I didn't measure correctly or if there are really no performance differences.
Do you think there are significant performance improvements in using async:true
over async:false
or is this at best a micro-optimization? One side note: we are only interested in results for modern browsers