Appearance
Basic Website Loading
When a website is loaded, first the HTML is requested. When the response has been read, the DOM tree will be created, then the CSS tree, after both have been parsed the render tree is generated which will trigger layout computations and finally paint the website.
The above steps are repeated multiple times. First paint is absolutly possible before DOM tree has been created completly. Painting the website is a gradual process.
When the HTML resource is loaded and the DOM tree is rendered completly, the DOMContentLoaded event is triggered. In contrast, the load event is triggered when the all resources have been loaded (HTML, stylesheets and images etc.). Note that usually DOMCOntentLoaded comes before load, but not necessarily.
Website Loading with JavaScript
When JavaScript is involved, then things do change. When JS <script> is detected, it needs to make sure that all CSS and HTML that has been detected up to now, is parsed. As CSS scripts are usually located in the header, this means the JS may wait for the complete CSS resource to be downloaded and wait for the rendering of the CSS tree before the JS is executed. In addition the JS will also wait for the DOM tree to be parsed until the JS script was detected. Now the script will be executed and block the rendering of the CSS and HTML tree.
That is the reason, why it is recommended to put the <script> tag always at the end of the <body> section, as the DOM and CSS tree would be rendered first completly (almost as the </body> is missing in DOM tree). However, this means the website will wait until DOM and CSS tree are complete, and then it will start to download the JS resource. Luckily, a developer has the following options to improve the flow.
Inline
The script will be executed and block DOM/CSS tree. As there is nothing to download, this is an improvement. But it also has the downsite that it makes importing scripts for your website cumbersome and also does not allow the browser to use caching functionality.
Defer
Put the <script defer> tag in the header. The defer attribute will request the resource and download in while the website is build, but it will trigger the JS only when the DOM tree is rendered. The JS will be executed before the event DOMContentLoaded is executed.
The benefit of this tag is that script can be downloaded in parallel while the render tree is parsed.
Defer can be used for script tags that reference to a remote file, as well as scripts that are inline.
Async
Using <script async> attribute will request the resource and download in while the website is build, it will trigger the JS as soon as the code is available. This download of the JS resouce does not block DOM/CSS tree rendering, but the execution of the script does.
Async can be used for scripts that reference to a remote file, as well as scripts that are inline (although it makes no difference for the latter, as there is nothing to download).
DomContentLoaded Event
You can write an event listener that waits to execute the code once the DOM tree has been created.
Load Event
If your JS changes the image size or any other resource, its probably best to wait till all resources have been loaded. Note that load alone does not guarantee that the DOM tree has been created. If you need both, you could load your script using defer and wait in the script for the load event.