Sync (without keyword)
If during HTML parsing a JS element is found, the parsing gets stopped until the script is (downloaded and) executed.
– If it relies on the HTML DOM, then put it at the end of the <body>.
<script src="/path/to/script.js"></script>
Async
If during HTML parsing a JS element is found, (the script gets downloaded in parallel but) its execution blocks the parsing if not finished then.
– They don’t block the DOMContentLoaded, but the window.onload event.
<script src="/path/to/script.js" async></script>
Defer
If during HTML parsing a JS element is found, (the script gets downloaded in parallel but) its execution happens just after the parsing is finished.
– They are getting executed before the DOMContentLoaded event gets fired.
– The scripts are executed in the order they occur in the HTML document.
<script src="/path/to/script.js" defer></script>
Usage
Prefer async over defer over sync, if possible.
– Use async if the script isn’t relying on other scripts1 or the HTML DOM.
– Use defer if the script is relying on other scripts2 or the HTML DOM.
– Use sync if async scripts rely on it or the browser isn’t supporting async/defer.
1 Execpt sync scripts placed before it.
2 Except async scripts of course. 🙂
Source: Growing with the web