HTML과 CSS를 통해 웹 페이지의 뼈대와 살을 붙여봤다면, 이제 JS를 이용해 페이지가 살아 숨 쉬도록 해줘야 할 차례다.
HTML 파일에다 link 태그를 통해 CSS를 불러온 것과 유사하게, JS 파일도 불러와서 사용해야 하는데
어떤 위치에서 혹은 어떤 속성을 통해 사용하느냐에 따라 실행되는 시점이 달라지고
이에 따라 페이지 성능에 차이가 발생할 수 있다.
갑작스레 등장하는 들기름 아니 스크립트를 어떻게 제어할 수 있을지 알아보자.
head vs body
// index.html
<html lang="kr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link href="./style.css" rel="stylesheet" />
<script src="./app.js"></script> // 1번
</head>
<body>
<h1>Hello!</h1>
<script src="./app.js"></script> // 2번
</body>
</html>
// app.js
console.log("hello world")
첫 번째 방법으로는 head 태그 사이에 script 태그를 통해 불러오는 것이다.
src 속성에다가 불러오고 싶은 js 파일의 경로를 작성하면 된다.
두 번째 방법으로는 body 태그 가장 마지막 부분에서 불러오는 것이다.
사용 방법은 첫 번째 방법과 동일한데 불러오는 위치만 달라진다고 보면 되겠다.
그럼 이 둘의 차이는 뭘까?
컴퓨터가 HTML 문서를 위에서부터 쭉 읽어 내려가다가 script 태그를 만나면
읽는 것을 멈추고 script 태그에 연결된 JS 파일을 다운로드한 뒤 스크립트를 실행한다.
그럼 1번의 경우에는 화면이 그려지기 전 script를 실행하는 구조고,
2번의 경우는 화면이 그려지고 난 뒤 script를 실행하는 구조다.
// index.html
<html lang="kr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link href="./style.css" rel="stylesheet" />
<script src="./app.js"></script> // 1번
</head>
<body>
<h1>Hello!</h1>
<script src="./app.js"></script> // 2번
</body>
</html>
// app.js
..엄청 복잡한 로직으로 구성되어 있음
만약 app.js 안의 코드가 굉장히 복잡하고 연산이 오래 걸리는 로직으로 구성이 되어있다고 가정해 보자.
그렇다면 1번의 경우에는 사용자 입장에서 화면이 실제로 보이기 전까지 굉장히 오랜 시간이 소요가 되겠다.
하지만 2번의 경우에는 화면이 그려지고 난 뒤 스크립트가 실행되기에,
사용자 입장에서는 화면을 일단 볼 수 있는 상태가 되겠다.
근데 화면을 일단 볼 수 있다고 하더라도 스크립트를 읽고 있는 중이기 때문에
사용자가 페이지 내에서 아무런 상호작용을 할 수 없을 수도 있다.
Async vs Defer
// index.html
<html lang="kr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link href="./style.css" rel="stylesheet" />
<script async src="./app.js"></script>
<script defer src="./app.js"></script>
</head>
<body>
<h1>Hello!</h1>
</body>
</html>
그래서 이번에는 script 태그에서 사용할 수 있는 속성을 알아보자.
알아볼 속성으로는 async와 defer가 있는데 두 속성의 공통점과 차이점을 본다면
공통점은 head 태그 사이에 사용한다는 것, HTML 파싱과 병렬적으로 우선 js 파일을 다운로드한다는 것이다.
그럼 차이점에는 어떤 것이 있을까?
우선 async는 위의 사진과 같은 특징을 가지게 되는데,
HTML 파싱 중 script를 만나게 되면 js 파일을 우선 다운로드하고,
다운이 완료가 되면 그 순간 화면을 그리는 것을 멈추고 스크립트를 실행하게 된다.
<html lang="kr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link href="./style.css" rel="stylesheet" />
<script async src="./app.js"></script> // fetch 0.6s
<script async src="./app2.js"></script> // fetch 1s
<script async src="./app3.js"></script> // fetch 0.2s
</head>
<body>
<h1>Hello!</h1>
</body>
</html>
async 방식에서 또 고려해야 하는 부분이 있는데,
여러 개의 스크립트가 있는 경우에 다운 완료된 순서대로 스크립트가 실행되다는 특징이 있다.
위의 코드를 기준으로 보면, app3 -> app -> app2의 순서대로 스크립트가 실행되는 것이다.
만약 순서에 의존한 스크립트 구조라고 한다면 스크립트가 상당히 꼬일 수 있는 구조가 될 수 있다.
defer의 경우는 HTML 파싱 중 js 다운을 받는데 다운이 완료되었다고 하더라도
파싱을 멈추지 않고 모두 화면이 그려졌을 때 js 스크립트를 실행한다.
또한 defer는 다운 완료된 순서와 관계없이, 순서대로 스크립트가 실행된다는 특징이 있다.
js 스크립트에 따라서 다르긴 하겠지만,
일반적인 흐름에서는 defer 속성을 사용하는 것이 가장 효율적일 수 있겠다.
그러나 스크립트가 다른 파일에 종속적이지 않고, 자체적으로도 종속성이 없는 스크립트의 경우
async가 유리하다고 하는 내용도 있으니 상황에 맞춰서 사용하는 것이 가장 좋겠다.
포스팅 작성에 참고한 감사한 글들
'Stack > HTML' 카테고리의 다른 글
input 태그의 inputmode 속성 : 가상 키보드 타입 지정하기 (0) | 2024.12.02 |
---|---|
section과 article : 같은 듯, 다른 듯 애매한 둘 (1) | 2024.11.03 |
attribute와 property의 차이 : 아니 왜 같은 속성인데 왜 달라요? (0) | 2024.10.17 |
DOM이란? : 돔돔 돔돔 돔돔 (1) | 2024.10.16 |
HTML은 프로그래밍 언어인가요? (0) | 2024.09.25 |