웹 페이지는 기본적으로 위에서 아래로, 순서대로 파싱됩니다. 만약 <script>
태그를 중간에 만나면 파서는 해당 스크립트를 다운로드하고 실행한 뒤에야 페이지의 나머지 부분을 파싱하게 됩니다. 이렇게 되면 스크립트의 다운로드 및 실행 시간 동안 웹 페이지의 렌더링이 중단됩니다.
<script src="script.js"></script>
<div>...</div>
예를 들어서 script
태그가 10초 이상 걸린다고 가정할 경우 div
태그는 10초를 기다리고 나서 파싱 되는 상황이 발생하게 됩니다. 그래서 많은 자료를 찾아보면 <body>
태그가 끝나고 나서 script
를 모아서 처리하는 방식을 사용합니다. 그러나 이 방식도 문제가 될 수 있는 것이 아래와 같이 되어 있을 경우
</body>
<script src="script.js"></script>
만약 scrpit
태그가 위 body
태그 안에 있는 태그와 호환해야 하는 경우 이미 웹페이지가 사용자에게 보여지고 있는 상황에서 scrpit
가 아직 파싱이 되지 않은 상황에서 사용자가 해당 태그를 클릭하게 되면 에러가 발생할 수 있어 위 방식도 궁극적인 해결방식은 아닙니다. 이를 막기 위해 아래와 같은 설정값을 넣어주면 됩니다.
async
속성이 있는 스크립트는 비동기적으로 다운로드됩니다. 즉, 스크립트의 다운로드가 HTML 파싱과 병렬적으로 진행됩니다. 그러나 다운로드가 완료되면 파싱은 잠시 중단되고 스크립트가 실행됩니다.
<script src="script.js" async></script>
async
의 경우에는 정말 독립적으로 진행되는 태그가 아니라면 사용하지 않는 것이 좋습니다. (서드 파티에 사용하는 경우가 좋습니다.)
defer
속성이 있는 스크립트도 비동기적으로 다운로드됩니다. 하지만, 스크립트의 실행은 HTML 파싱이 완전히 끝난 후에 이루어집니다. 이것은 페이지의 렌더링이 중단되지 않도록 도와줍니다.
<script src="script.js" defer></script>
비동기 다운로드: async
와 defer
둘 다 스크립트의 다운로드를 비동기적으로 합니다.
실행 순서: async
는 다운로드가 먼저 끝난 스크립트부터 실행됩니다. 따라서 순서를 보장하지 않습니다. 반면 defer
는 HTML 문서의 순서대로 스크립트가 실행됩니다.
파싱 지연: async
는 스크립트 다운로드 후 즉시 실행되므로 HTML 파싱이 중단될 수 있습니다. 반면 defer
는 파싱이 완전히 끝난 후에 실행됩니다.
스크립트가 문서의 파싱에 의존적이지 않고, 문서의 파싱을 방해하지 않아도 된다면 async
를 사용하는 것이 좋습니다.(여러 글을 찾아본 결과 async
보다는 defer
를 사용하라고 되어 있네요...)
스크립트가 다른 스크립트의 실행 순서에 의존적이거나, 파싱 후에 실행되어야 한다면 defer
를 사용하세요.
마지막으로, 이 두 속성은 외부 스크립트(즉, src 속성을 가진 스크립트)에만 적용됩니다.