Umieszczenie obu atrybutów: async i defer powoduje, że gdy przeglądarka nie wspiera jednego, to użyje drugiego jako fallback. Wspólna cecha obu atrybutów to sprawienie, że skrypt jest pobierany w tle, nie blokując parsera DOM.
Powyższe atrubyty różni natomiast moment, w którym skrypt będzie wykonany (uruchomiony). defer powoduje, że skrypt odpali się tuż przed event-em DOMContentLoaded (czyli prawie tak, jakbyś umieścił skrypt przed zamykającym </body>) i kolejność wykonania skryptów z atrybutem defer będzie zachowana. W przypadku async skrypt wykona się po pobraniu - jeśli zdąży pobrać się np. w połowie parsowania strony, to wykona się właśnie wtedy (blokując dalsze parsowanie DOM na ten czas), jeśli pobierze się po sparsowaniu DOM, to dopiero wtedy się wykona - więc moment uruchomienia jest mniej przewidywalny.
Do poczytania: https://javascript.info/script-async-defer