<script>, are render blocking, both inline and fetched scripts. That means that the browser will both fetch and evaluate the script before it continues rendering the page. From the notes section of the MDN docs on the script element
Scripts... are fetched and executed immediately, before the browser continues to parse the page.
The reason why is because the script could manipulate the rendering itself. The browser trusts that the HTML author placed the script where they did for a good reason, and so should fetch it, evaluate it, and do what it says immediately.
Oftentimes, the HTML author does not want to slow down the rendering of the page to fetch and evaluate a script that will have no impact on the (initial) rendering of the page. In such cases, it is recommended to use the
async will fetch the script off the main thread. So, for both, fetching does not block rendering of the page. The difference is when the script is evaluated.
async will evaluate the script immediately, so, once it's been fetched.
defer will evaluate the script as the last action before finishing the parsing of DOM content, signaled by the document DOMContentLoaded event (a precondition to the more commonly known window
I think that the rule of thumb for a regular web dev is to use
defer by default, and that you will know when to violate that rule and use
async, or even parser/render-blocking regular scripts.
defer is the least obtrusive.