결론부터 말하면 script태그는 <body>
태그의 닫는 태그 바로 앞에 위치해주는 것이 좋습니다.
<body>
<script src ="./index.js"></script>
</body>
서버로부터 응답받은 html문서는 렌더링되기 위해 파싱되어야합니다.
파싱(parsing)
파싱이란 컴퓨터가 해당 문서를 인식하기위해 html문서의 텍스트들을 컴퓨터가 이해 가능한 언어로 변환하는 과정입니다.
<head>
<script src ="./index.js"></script>
</head>
파싱을 할 때에 위에서부터 아래방향으로 진행되는데 이 때 만약 script태그가 <head>
태그의 닫는 태그 뒤에 위치한다면 dom이 생성되기전에 script가 존재하지않는 dom을 건드리는 dom API을 사용한다면 에러가 발생할 수 있습니다.
때문에 script태그는 기본적으로 <body>
의 닫는 태그 바로 앞에 위치시키는 것이 좋습니다.
<script>
태그를 만나게 되면 html 파싱이 일시중지되고 js파일을 파싱하게 됩니다.
<head>
태그의 닫는 태그 앞에 <script>
를 위치시키면 js파일을 파싱하는 시간만큼 대기를 해야하기 때문에 그만큼 html 파싱을 하는데 시간이 오래걸릴 것 입니다.
때문에 페이지 로딩 속도가 느려질 수 있습니다.
위처럼 <head>
태그의 닫는 태그 앞에 <script>
태그를 위치시키면 HTML의 DOM 생성이 중단된다는 단점이 있었습니다.
이를 해결하기위해 script 태그에는 async와 defer라는 속성이 있습니다.
async와 defer 어트리뷰트를 사용하면 HTML 파싱과 자바스크립트의 파일 로드가 비동기적으로 동시에 진행됩니다.
<script async src="./index.js"></script>
HTML 파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행됩니다.
단, 자바스크립트의 파싱과 실행은 자바스크립트 파일의 로드가 완료된 직후에 진행되며, 이 때 HTML 파싱은 중지됩니다.
여러 개의 script 태그에 async 어트리뷰트를 지정하면 script 태그 순서와 상관없이 완료된 자바스크립트부터 먼저 실행되기 때문에 순서가 보장되지 않습니다.
따라서 순서 보장이 필요한 script 태그에는 async 어트리뷰트를 지정하지 않아야합니다.
<script defer src="./index.js"></script>
async 어트리뷰트와 마찬가지로 HTML 파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행됩니다.
단, 자바스크립트의 파싱과 실행은 HTML 파싱이 완료된 직후, 즉 DOM 생성이 완료된 직후 진행됩니다. 따라서 DOM 생성이 완료된 이후 실행되어야할 자바스크립트에 유용합니다.
따라서 왠만하면 script태그를 body 태그의 닫는 태그 앞에 위치시키거나 script 태그에 defer 속성을 입력해주는 것이 좋습니다.