외부 script 호출시 async와 defer 속성

브라우저는 html 파일의 위에서 부터 아래로 쭉 읽는다.

또한, 기본적으로 웹 브라우저는 html을 랜더링 할 때 css 또는 js를 만나면 동기적으로 처리한다.
( 해당 내용이 해석 및 실행되기 전에는 뒤에 나오는 내용을 처리하지 않음 )

<script type="text/javascript" src="./js/test.js"></script>

이 부분은 해당 웹의 렌더링 속도에 큰 영향을 줄 수 있다. 만약, 서버가 받아와야할 js 사이즈가 크다면, fetching 하고 executing하는데 시간이 상당히 소요될수있다.

css의 경우에는 화면을 랜더링하는데 필요한 정보를 담고 있으므로 내용을 출력하기 전에 해석되는 것이 좋다. (화면이 여러번 랜더링 되는 것을 줄일 수 있다)

js의 경우에는 대부분 화면 출력과 관계가 있기 보다는 기능적인 처리에 관련되어있는 경우가 많다. (웹앱과 같이 출력과 직접적인 관련이 있더라도 이 또한 기본적인 화면이 출력된 이후에 처리되는 것이 웹 페이지를 빠르게 렌더링하는데 유리하기 때문에 처리를 지연하는 것이 좋다)

이러한 이유로 css는 <head> 영역에, js는 </body> 바로 앞에 선언하는것이 권장되었다. 이 방법은 오래된 브라우저에서도 동일한 효과를 얻는 좋은 방법이다.

하지만, js를 </body> 바로 앞에서 호출할 시 사용자가 웹페이지 컨텐츠를 빨리 볼수있다는 장점은 있지만, 만약 웹사이트가 자바스크립트에 굉장히 의존적이라면 문제가 될 수 있다. (사용자가 의미있는 컨텐츠를 보기위해 서버에 있는 데이터를 받아와야 한다던지, DOM요소를 더 이쁘게 꾸며야한다던지..)

하지만 이 방법 외에도 <script>에는 async 속성과 defer 속성을 사용하는 방법이 있다.

일반적인 실행

기본적으로 <script>는 인라인 코드의 경우 즉시 해석되고 실행될 수 있지만 그렇지 않은 경우는 해당 파일을 가져올 때까지 HTML 문서의 구문 분석(HTML,CSS를 파싱하여 DOM요소로 만듦)을 중단한다. 이 경우에, 페이지가 로드 될때까지 시간이 늘어날 수 밖에 없고, 스크립트가 DOM요소를 참조한다면 문제가 될 수 있다.

async 속성이 추가된 경우의 실행

<script async src="script.js"></script>

async 속성을 사용하면 파일이 비동기적으로 실행될 수 있다. 이는 HTML 문서가 분석 되는 동안 스크립트 파일을 다운로드(병렬) 할 수 있으며 다운로드가 완료되면 스크립트가 실행될 수 있도록 구문 분석이 일시 중지 된다. js파일을 다운로드 하는데에 시간이 절약되긴 한다.

하지만 , 실행 순서가 중요한 스크립트의 경우에는 문제가 발생할 수있다. 예를 들어 script가 html에 의존적일 경우 (DOM이 완전히 해석되어야만 정상 동작이 가능한 경우)에는 모든 내용이 파싱된 후에 동작하도록 해야한다. 이러한 경우에는 defer 속성 혹은 </body> 태그 앞에 스크립트 로드를 사용하는게 유리하다.

다른 파일들에 종속적이지 않는 스크립트 파일의 경우에는 async 속성이 유용하다.

defer 속성이 추가된 경우의 실행

<script defer src="script.js"></script>

defer 속성과 async의 가장 큰 차이는 defer 속성은 HTML 구문 분석이 완전히 완료되면 스크립트 파일을 실행하도록 브라우저에 지시한다는 것이다.

async와 마찬가지로, HTML 구문 분석이 실행되는 동안 파일을 다운로드 할 수 있다. 그러나 HTML 구문 분석이 완료되기 전에 스크립트 다운로드가 완료되더라도 구문 분석이 완료 될 때까지 스크립트는 실행되지 않는다.

대부분의 경우 스크립트 파일에는 DOM과의 상호 작용이 필요한 기능이 포함되어 있거나 페이지에 포함된 다른 파일에 대한 종속성이 있을 수 있다. 이러한 경우 스크립트를 실행하기 전에 DOM이 완전히 해석되어야 정상적인 동작을 할 수 있다. 일반적으로 이러한 스크립트 파일은 페이지의 맨 아래에 배치되어 모든 내용이 파싱된 후에 동작하도록 해야 한다. 어떤 이유로 든 문제의 파일을 다른 위치에 배치해야 하는 상황에서는 defer 속성을 사용할 수 있다.

또, async과 defer의 차이점은 실행되는 js파일의 순서를 결정할 수 있냐의 여부이다.

async 속성은 실행 순서를 결정할 수없다. 먼저 다운로드 된 순으로 실행
defer 속성은 실행 순서를 결정할 수 있다.

defer , async 를 지원하는 브라우저

  • IE는 defer의 경우 예전부터 부분 지원하고 있으나 async 속성은 10 버전 이상부터 지원(defer 완전 지원 포함)
  • Firefox는 3.6 버전부터 모두 지원
  • chrome은 8 버전부터 모두 지원
  • safari는 5 버전부터 모두 지원(단, 5버전에서는 async=false 지원 안함)
  • ios safari는 5.1 버전부터 모두 지원
  • android는 3 버전부터 모두 지원

결론 : </body> 바로 앞에 스크립트를 위치시키거나, defer 속성을 쓰는게 나을 듯 하다. 만약 스크립트 사이즈가 작고, 다른 파일에 종속적일 경우에는 그냥 인라인으로 정의하는게 나을 수도 있다고 한다.

참조 : https://blog.asamaru.net/2017/05/04/script-async-defer/