These two attributes tell browsers how to handle elements
Without any attributes on the script element a HTML file will be parsed until the script file is hit, parsing will then stop and the file read (and fetched if external). After reading the file it will then be executed and HTML parsing will continue.
Using async means that the browser continues to parse the HTML as it encountered the script. Once it's been downloaded/read the HTML will stop parsing and the script executed, before the parsing continues again.
<script async src="app.js">
Using defer means that the script will be read while the HTML is parsing. Only when the parse is complete will the script execute.
<script src="app.js" defer="defer">
Other than on smaller 3rd party scripts I'm struggling to understand why either should be used over the traditional "put before the closing body tag" method?
If the scripts are before the closing body tag then the HTML will be parsed before it's executed anyway, this is essentially deferring? You could put the script into a head and use defer, so that it's ready to execute when parsing is finished but will this be any faster? Unless the browser is able to parse HTML and read JS at a faster rate than it would without async and defer?
I have lots of articles that suggest using async for analytics, which I understand as you don't care when the hell it runs. But shouldn't you let that script run after the page has loaded? So not to delay the loading times for the user?
Async shouldn't be used on anything that relies on another thing, such as a library. Say you've two files - the jQuery library and an app script that makes use of this library - which both have async attributes, if your script loads before the library it's going to throw some errors.