본문으로 바로가기

defer, async 스크립트

category JavaScript 2021. 7. 12. 20:40

스크립트 로드

html은 위에서 부터 코드를 하나씩 불러 브라우저에 표시해 사용자에게 보여주고 이러한 특성 때문에

일반적으로 html 파일에서 script를 불러오는 <script>태그는 때는 html의 제일 마지막에 위치한다

html 마크업을 표시하다가 script를 만난 시점에 script를 다 불러오기 전 까지 html을 읽는 것을 잠시 중단하기 때문

<body>
    <div>...</div> // 1번

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

    <div>...</div> // 2번
</body>

불러올 html이 이런 식의 구조를 가지고 있다면 1번을 불러온 뒤 스크립트를 불러오는 동안 2번의 마크업은 읽는 것이 중단되고

스크립트를 다 불러오기 전 까지는 사용자는 반쪽짜리 화면만 볼 수 밖에 없고 사용자는 페이지가 멈춘 것 처럼 느낄 수도 있게된다

그래서 보통은 다음과 같이 코드를 작성한다

<body>
    <div>...</div>
    <div>...</div>
    <script src="..."></script>
    <script src="..."></script>
    <script src="..."></script>
    <script src="..."></script>
</body>

이렇게 해도 문제는 생길 수 있다

html 자체의 크기가 너무 크고 거기에 script 마저 크다면 html을 한 세월 걸려서 다 받고... script도 한 세월 걸리게 되는데

이 경우에는

  1. 페이지 자체가 사용자에게 완전한 서비스를 제공하는데 까지 시간이 너무 오래걸린다
  2. html을 다 받아 사용자에게 온전한 화면은 보여주지만 script를 불러오는 동안에는 페이지가 불완전하게 작동한다

defer script

위 문제를 해결할 수 있는 문법이 중 하나는 defer

이 속성이 있는 스크립트는 브라우저가 즉시 불러오지 않고 백그라운드에서 불러온다

즉, html을 읽다 defer script를 만나면 html은 그대로 불러오면서 뒤에서 스크립트 또한 동시에 불러오는 것

그리고 스크립트를 다 불러오는 것을 완료했다고 해서 즉시 실행되지 않고 페이지가 완벽하게 불러와질 때 까지 실행이 지연된다

<body>
    <div>...</div> // 1번

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

    <div>...</div> // 2번
</body>

1번이 불러와진 후 2번과 defer script가 동시에 불러와진다

다음을 보자

<body>
<div>...</div> // 1
<script>
    document.addEventListener('DOMContentLoaded', () => alert('DOMContentLoaded')); // 2
</script>

<script defer src="./test.js"></script> // 3
<div>...</div> // 4
</body>
// in test.js
alert('defer');

페이지 구성이 끝날 때 까지 실행이 지연되는 defer script와 DOM 로드가 끝나고 나서 실행되는 이벤트인 DOMContentLoaded 가 같이 있다면 순서는 어떻게 될까?

1 - 4 - 3 - 2 다

defer가 먼저 실행되고 나서 DOMContentLoaded가 실행된다

defer script끼리의 순서

스크립트의 용량이 100인 big.js와 1인 small.js가 다음 처럼 불러와지고 있다

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

우선 브라우저는 스크립트들을 전부 살펴본 후에 병렬적으로 다운로드한다

big과 small의 다운로드가 병렬로 시작되는데 당연하게도 small의 다운로드가 먼저 끝난다

하지만 스크립트를 문서에 추가한 순서대로 실행되게끔 설계되어있기 때문에 big이 실행될 때까지 기다린 후 small이 실행된다


defer script는 항상 html이 완전히 로드된 후에 실행된다는 것을 유의해야한다

이는 사용자는 여전히 html이 완전히 로드될 때 까지 defer script를 사용하지 못한다는 것을 의미하는데

사용자를 위해 적절한 로딩 표시나 해당 스크립트의 기능 사용이 불가능함을 표시해주어야한다

async script

async script도 defer와 비슷하게 코드를 만났을 때 백그라운드에서 로딩하지만 페이지와 독립적으로 동작한다

  • async script는 페이지의 로드가 끝나는 것을 기다리지않고 스크립트 로드가 완료되면 바로 실행한다 (이 때 스크립트 실행중에는 html 로드가 멈추게 된다)
  • DOMContentLoaded와 같이 있을 때 서로를 기다리지 않는다
  • 스크립트 순서에 상관없이 먼저 다운로드된 스크립트가 먼저 실행된다 (이를 'load-first’ order라고 부른다)

동적 스크립트

자바스크립트를 이용해서 동적으로 스크립트를 추가해 줄 수 있다

    let script = document.createElement('script');

    script.src = "/path";
    document.$someElem.append(script);

이 코드에서 document.$someElem.append(script);가 실행될 때 path에 있는 스크립트의 다운로드가 시작되는데 이 때 스크립트는 동적 스크립트(async script)로 행동한다

그렇기 때문에 위에서 나열한 async script와 동일한 특성을 갖는다

이 특성은 script.async=false옵션으로 끌 수 있다


async script는 페이지와 완전히 독립적으로, 순서가 없이 실행되기 때문에 방문자 수를 나타내거나, 광고와 관련된 스크립트 등 페이지를 이용하는데 전혀 문제가 없는 기능들이어야 한다

'JavaScript' 카테고리의 다른 글

Object.defineProperty  (0) 2021.09.06
클래스, 믹스인 (Mixin)  (0) 2021.07.13
주요 노드 프로퍼티  (0) 2021.07.09
DOM 수정  (0) 2021.07.08
modal에 keydown 이벤트 추가하기 (tabindex)  (0) 2021.06.02