프론트엔드 강사가 알려주는~ 시리즈의 첫 번째 글입니다 :)
이번 글에서는 아래의 질문에 대해 작성해볼게요.
이 질문에서는 script, async 그리고 defer까지 총 3개의 용어가 나오는데요, 하나씩 차근차근 파악해보겠습니다.
HTML의 script
태그는, 웹 페이지에 자바스크립트를 삽입하거나 외부 스크립트를 로드하기 위해 사용됩니다. 자바스크립트는 웹 페이지의 동적 동작, 상호작용, 데이터 처리 등을 가능하게 하는 프로그래밍 언어라고 할 수 있고, script
태그를 통해 웹 브라우저에서 실행됩니다.
// 자바스크립트 코드 삽입
<script>
console.log(hello);
</script>
// 외부 스크립트 로드
<script src="script.js"></script>
외부 스크립트를 연결할 때에는 위와 같이 src 속성을 사용해 외부 자바스크립트 파일을 가져올 수 있습니다.
script
태그는 HTML 문서에 삽입되면 기본적으로는 동기적으로 실행이 되는데요, 그렇기 때문에 브라우저는 스크립트를 다운로드하고 실행할 때 HTML 파싱을 중단합니다.
갑자기 HTML 파싱이 중단 된다는게 무슨말이지? 라는 생각이 들었다면, 먼저 웹 브라우저의 렌더링 과정을 이해해야합니다. 렌더링 과정은 아래의 그림으로 간단하게 살펴볼 수 있습니다.
- HTML을 전달 받으면 HTML 파서를 통해 DOM 트리 형성
- Style Sheets 파싱 후 스타일 규칙 생성
- DOM 트리와 생성된 스타일 규칙 Attachment
- Render 트리 형성 후 Layout, Painting
- Display
script 태그는 기본적으로 '동기적'으로 실행되기 때문에, 웹 브라우저의 HTML Parser는 HTML 문서를 위에서 아래로 쭉 파싱하다가, script 태그를 만나면 HTML 파싱을 중단합니다. 그 다음, 스크립트를 로드하고 실행하고 다시 HTML 파싱을 이어나가죠.
위의 설명을 다시 말해보면, 자바스크립트 파일의 다운로드 및 실행 시간이 길어질수록, 최종 단계인 Display 단계가 지연된다고 할 수 있습니다.
Display 단계가 지연된다는 것은 페이지 요소들이 늦게 렌더링된다는 것을 의미하며, 이는 사용자 경험에 부정적인 영향을 미칩니다.
이러한 문제를 해결하기 위한 방법은 크게 3가지가 있습니다.
- script 태그를 body 태그의 가장 아래에 작성
- async 속성 사용
- defer 속성 사용
script 태그를 body 태그의 가장 아래에 작성하면, 별도의 속성을 사용하지 않고 문제를 해결할 수 있다는 장점이 있지만, 모든 스크립트를 반드시 body 태그의 아래에 작성해야하므로 코드의 가독성이 떨어질 수 있다는 단점이 있습니다.
그럼 이제 2,3 번째 방법인 async와 defer에 대해 배워보겠습니다.
async 속성을 사용하면, Display 단계가 지연될 수 있는 문제를 해결할 수 있습니다. async 속성은 '비동기적'으로 여러 스크립트를 로드하고 실행하는 속성으로 다음과 같이 작성합니다.
<script async src="script.js"></script>
script 태그에 async 속성을 작성하면, 스크립트를 비동기적으로 로드하기 때문에 HTML 파싱과 동시에 스크립트를 다운로드 및 로드합니다. 그리고 모든 스크립트가 로딩되는 즉시 스크립트를 실행합니다. 이 과정을 그림으로 나타내면 다음과 같이 나타낼 수 있습니다.
async 속성은 '스크립트 로드가 완료되면 그 즉시 스크립트를 실행한다' 라는 특징으로 인해, 스크립트가 여러개 존재할 경우 이들의 실행 순서를 보장하기 어렵다는 특징이 있습니다. 제일 첫번째로 로딩이 끝난 스크립트가 가장 먼저 실행이 되겠죠.
async 속성의 특징을 정리하면, 다음과 같이 정리할 수 있습니다.
스크립트를 비동기적으로 로드하며, 스크립트 다운로드와 로딩이 끝나면 스크립트를 즉시 실행한다. 따라서 스크립트들 간의 실행 순서를 보장하기 어렵다.
그럼 이번엔 또 다른 속성인 defer에 대해 살펴봅시다. defer 속성 또한 스크립트를 비동기적으로 로드하는 속성인데요, async와는 다른점이 있습니다.
<script defer src="script.js"></script>
defer 속성을 작성하면 스크립트가 어떻게 로드되고 실행되는지 먼저 그림으로 확인해보겠습니다.
그림을 확인해보니, async와 다른점이 한눈에 보이죠?
async 속성을 사용하면 스크립트가 비동기적으로 로드되고 스크립트가 로딩된 즉시 실행되지만, defer 속성을 사용하면 스크립트가 비동기적으로 로드되며 스크립트 로딩이 끝났더라도, HTML 파싱이 완료된 후 스크립트 파일이 실행됩니다.
이러한 특징때문에 defer 속성을 사용하면, async와는 다르게 스크립트들의 순서가 보장된다는 특징도 있습니다. 하지만 defer 속성은 외부 스크립트에서만 동작하는 속성이기 때문에 주의해서 사용해야합니다.
스크립트를 비동기적으로 로드하며, 스크립트 다운로드와 로딩이 끝나더라도 HTML 파싱이 종료된 이후에 스크립트가 실행된다. 따라서 스크립트들 간의 실행 순서를 보장할 수 있다. 하지만 외부 스크립트에서만 동작한다.
여러 스크립트들이 서로 관련되어있지 않아 실행 순서가 보장되지 않아도 괜찮다면 async 속성을, 그리고 실행 순서가 중요한 스크립트이면서 외부 스크립트라면 defer 속성을 사용하면 되겠죠.
이렇게 async와 defer 속성에 대해 아주 자세하게 작성해보았는데요, 글을 읽는 분들 모두 완변하게 이해하고 가셨으면 좋겠습니다 😊
어려운 내용이나 이해가 가지 않는 내용이 있다면 댓글로 알려주세요!!
감사합니다.
이런게 있는지도 몰랐네요. 좋은 정보 감사합니다.