브라우저의 동작 이해

khxxjxx·2023년 10월 13일
0

시작하기 전 용어 설명

  • 컴퓨터나 스마트폰 애플리케이션을 실행할 때 애플리케이션을 구동하는 것이 바로 CPU와 GPU입니다.
  • 애플리케이션을 시작하면 프로세스가 하나 만들어지고 프로세스가 작업을 하기 위해 스레드를 생성할 수 있습니다.
  • 프로세스는 여러 작업을 수행하기 위해 운영체제에 다른 프로세스를 실행하라고 요청할 수 있고 두 프로세스가 서로 정보를 공유해야 할 때는 IPC(inter process communication, 프로세스 간 통신)를 사용합니다.
    • CPU : 컴퓨터의 두뇌로 여러 종류의 작업을 하나씩 순서대로 처리 할 수 있습니다.
    • GPU : 그래픽 작업 처리를 위해 개발되어 CPU와 달리 간단한 작업에만 특화되어 있지만 여러 GPU 코어가 동시에 작업을 수행할 수 있습니다.
    • 프로세스 : 애플리케이션이 실행하는 프로그램이라 할 수 있습니다.
    • 스레드 : 프로세스 내부에 있으며 프로세스로 실행되는 프로그램의 일부를 실행합니다.

브라우저란?

  • 웹 브라우저는 동기(Synchronous)적으로 (HTML + CSS), Javascript 언어를 해석하여 내용을 화면에 보여주는 응용 소프트웨어입니다.
  • 대부분의 브라우저는 웹 표준화 기구인 W3C의 명세에 따라 HTML과 CSS를 해석하게 되는데 이러한 과정을 파싱(parsing)이라고 합니다.
  • 웹 브라우저가 웹 서버에 필요한 자원(웹 페이지)을 요청하면 서버는 응답하고 웹 브라우저는 이를 해석한 후 사용자(Client)에게 보여줍니다. 보통 자원은 HTML 문서지만 PDF, 이미지 등 다양한 형태일 수 있습니다.
  • 웹 브라우저의 대표적인 예로 크롬, 네이버 웨일, 파이어폭스, 사파리 등이 있습니다.
  • 이 글에서는 크롬 브라우저를 기반으로 설명하겠습니다.

브라우저의 기본 구조

  • 사용자 인터페이스 : 주소 표시줄, 이전/다음 버튼, 홈버튼, 새로고침/정지 버튼 등 요청 한 페이지를 보여주는 창 외에 사용자가 컨트롤 할 수 있는 부분입니다.
  • 브라우저 엔진 : 사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어하며 자료 저장소를 참조하여 로컬에 데이터를 읽고 쓰면서 다양한 작업을 합니다. 
  • 렌더링 엔진 : 요청한 URI를 브라우저 엔진에게 받아서 server에게 요청(통신)하고 server로 부터 URI에 해당하는 데이터(HTML, CSS, JavaScript)를 받아서 파싱한 후 화면에 표시합니다.
  • 통신 : 렌더링 엔진으로부터 HTTP 요청 등을 받아서 네트워크 처리 후 응답을 전달합니다.
  • 자바스크립트 인터프리터 : JavaScript를 파싱(chrome V8)합니다.
  • UI 백엔드 : render tree를 browser에 그리는 역할을 담당합니다.
  • 자료 저장소 : 쿠키 등의 자료를 컴퓨터 하드디스크에 저장(HTML5부터 Web Database에 저장가능)합니다.

브라우저 아키텍쳐 구현 사항에 어떤 프로세스를 가져야한다는 표준은 없기때문에 어떤 프로세스는 하나의 프로세스에 여러 스레드가 있을 수도 있고, 스레드를 조금만 사용하는 프로세스를 여러 개 만들어 IPC로 통신할 수도 있습니다. 위 요소가 모두 동급의 프로세스 혹은 스레드 라기 보단 이러한 역할을 하는 요소들이 존재한다는 식으로 이해하면 좋습니다.


브라우저 아키텍쳐(Chrome)

  • 브라우저 프로세스: 주소 표시줄, 북마크 막대, 뒤로 가기 버튼, 앞으로 가기 버튼 등을 제어하고 네트워크 요청이나 파일 접근과 같이 눈에 보이지는 않지만 권한이 필요한 부분도 처리합니다.
  • 렌더러 프로세스: 탭 안에서 웹 사이트가 표시되는 부분의 모든 것을 제어합니다. 예전 렌더러 프로세스는 여러 개가 만들어져 각 탭마다 할당되었지만, 지금은 사이트(iframe 포함)마다 프로세스를 할당합니다.
  • 플러그인 프로세스: 웹 사이트에서 사용하는 플러그인(예: Flash)을 제어합니다.
  • GPU 프로세스: GPU 작업을 다른 프로세스와 격리해서 처리합니다. GPU는 여러 애플리케이션의 요청을 처리하고 같은 화면에 요청받은 내용을 그리기 때문에 GPU 프로세스는 별도 프로세스로 분리되어 있습니다.
  • 기타 프로세스: 확장 프로그램 프로세스, 유틸리티 프로세스 등의 프로세스가 있습니다.
  • 크롬 브라우저는 다양한 프로세스를 갖지만 그중 가장 기본이 되는 것은 브라우저 프로세스와 렌더러 프로세스 입니다. 하나의 브라우저를 실행하면 브라우저 프로세스는 단 한가지이며 렌더러 프로세스는 여러개 일 수 있습니다.
  • 크롬 브라우저가 멀티 프로세스로 구성된 이유는 브라우저에서 탭을 여러개 킨 상태에서 한 탭이 응답하지 않을때 싱글 프로세스의 경우 브라우저 전체가 종료될 수 있기 때문입니다. 또한 프로세스 분리를 통해 각 프로세스가 접근 가능한 메모리 범위를 격리하고 보호할 수 있는 장점이 있습니다.

브라우저 프로세스

  • 브라우저 프로세스는 탭 영역 밖에 있는 모든 부분을 제어합니다.
  • 사용자가 사이트를 요청하고 브라우저가 페이지 렌더링을 준비하는 과정을 내비게이션이라 합니다.
  • 브라우저 프로세스에는 UI 스레드와 네트워크 스레드, 스토리지 스레드 등이 있습니다.
    • UI 스레드 : 브라우저의 버튼과 입력란을 그리며 주소 표시줄에 URL을 입력하면 입력을 처리합니다.
    • 네트워크 스레드 : 인터넷에서 데이터를 가져오기 위해 네트워크 스택을 다룹니다.
    • 스토리지 스레드 : 파일에 대한 접근을 제어합니다.

내비게이션 과정

1) 입력처리

  • 사용자가 주소 표시줄에 타이핑을 시작하면 UI스레드는 먼저 입력되는 내용이 검색어인지 URL인지 확인합니다. UI 스레드는 입력되는 내용을 파싱해서 검색 엔진으로 이동할지 요청한 사이트로 이동할지 판별하는데 이때 이를 도와줄 서버와 통신하거나 DNS Lookup을 실행해서 결정합니다.

    DNS(Domain Name System)는 범국제적 단위로 웹사이트의 IP 주소와 도메인 주소를 이어주는 환경/시스템

2) 내비게이션 시작

  • 사용자가 Enter키를 누르면 사이트의 콘텐츠를 가져오기 위해 UI 스레드가 네트워크 호출을 시작합니다. 로딩 스피너가 탭의 모서리에 표시되고, 네트워크 스레드는 요청에 대한 DNS Lookup 및 TLS 연결 설정과 같은 적절한 프로토콜을 거쳐 요청을 처리합니다.
  • 이때 네트워크 스레드가 HTTP 301과 같은 서버 리디렉션 헤더를 수신할 수도 있습니다. 그런 경우에는 네트워크 스레드가 UI 스레드와 통신해 서버가 리디렉션을 요청했다는 것을 알린 후에 새로운 URL 요청이 시작됩니다.

    TLS(Transport Layer Security), TLS 프로토콜은 인터넷을 통한 통신 보안을 제공하며 클라이언트/서버 애플리케이션이 비밀이 유지되고 안정적인 방식으로 통신할 수 있도록 해줍니다

3) 응답 읽기

  • 응답 본문인 페이로드가 들어오기 시작하면 네트워크 스레드는 어떤 형식의 데이터인지 응답 헤더의 Content-Type 헤더를 확인합니다. 이 응답이 HTML파일 같이 렌더러 프로세스가 다룰 수 있는 데이터 형식 이라면 데이터를 렌더러 프로세스에 전달을 하게 되며, 응답이 ZIP형식 파일 같은 렌더러 프로세스가 다룰 수 없는 데이터 형식이라면 다운로드 매니저에 데이터를 전달하는 단계로 넘어가게 됩니다.
  • 또한 이 단계는 Safe Browsing의 검사가 실행됩니다. 도메인과 응답 데이터가 악성 사이트로 알려진 사이트와 일치하는 것 같다면 네트워크 스레드는 경고 페이지를 표시하라고 알립니다. 또한 CORB( Cross-Origin Read Blocking ) 기능이 서로 다른 사이트(cross-site)의 민감한 데이터가 렌더러 프로세스에서 실행되지 않게 검사합니다.

    CORB란 Ajax 호출을 필요로 하는 기능에서 보안상 이유로 동일 서버 이외에는 접근할 수 없도록 한것

4) 렌더러 프로세스 찾기

  • 모든 검사가 끝나고 요청된 사이트로 이동 해야할 때 네트워크 스레드가 UI 스레드에게 데이터가 준비되었음을 알립니다. 그러면 UI 스레드는 웹 페이지의 렌더링을 수행할 렌더러 프로세스를 찾게 됩니다.

    2단계 내비게이션 시작시 UI 스레드가 네트워크를 호출하면서 렌더러 프로세스를 먼저 찾거나 네트워크요청과 동시에 렌더러 프로세스를 시작할 수 있습니다. 이런 방식은 모든 것이 예상대로 잘 진행된다면 네트워크 스레드가 데이터를 받을 때 이미 렌더러 프로세스는 준비 상태에 있게 되지만 만약 다른 사이트로 리디렉션이 이루어져 다른 프로세스가 필요하게 되면 미리 준비한 프로세스가 사용되지 않을 수 있습니다.

5) 내비게이션 실행

  • 데이터와 렌더러 프로세스가 준비되었다면 내비게이션을 실행하도록 브라우저 프로세스에서 렌더러 프로세스로 IPC메세지를 전송합니다. 또한 렌더러 프로세스가 HTML 데이터를 계속 수신 할 수 있도록 브라우저 프로세스는 데이터 스트림을 전달합니다. 렌더러 프로세스에서 내비게이션이 실행되었다는 것을 브라우저 프로세스가 확인하고 나면 내비게이션이 완료 되고 문서 로딩 단계가 시작됩니다.
  • 이 시점에 주소 표시줄이 업데이트 되고 보안 표시와 사이트 설정 UI도 새 페이지의 사이트 정보를 반영해서 갱신됩니다. 탭에 대한 세션 기록이 업데이트되어 뒤로 가기 버튼과 앞으로 가기 버튼도 방금 이동한 사이트를 반영해 작동합니다. 탭이나 창을 닫은 이후 탭과 세션을 복원할 수 있게 세션 기록이 디스크 드라이브에 저장됩니다.

6) 로드 완료

  • 내비게이션이 실행되면 렌더러 프로세스는 계속 리소스를 로딩하고 페이지를 렌더링 합니다. 렌더러 프로세스가 모든 프레임에서 onload 이벤트의 실행까지 끝냈다면 브라우저 프로세스로 IPC메세지를 보냅니다. 그러면 UI 스레드는 탭에서 로딩 스피너의 작동을 중지 시킵니다.

렌더러 프로세스

  • 렌더러 프로세스는 탭 내부에서 발생하는 모든 작업을 담당합니다.
  • 렌더러 프로세스의 주요 역할은 서버로 부터 받은 HTML과 CSS, JavaScript를 사용자와 상호작용 할 수 있는 웹 페이지로 변환하는 것으로 이 과정을 렌더링이라고 합니다.
  • 렌더링은 렌더링 엔진과 엔진 내의 JS 인터프리터를 통해 이루어지며 렌더러 프로세스는 필요에 따라 워커 스레드를 이용하여 JS 코드의 일부를 처리하기도 하고 웹 페이지를 효율적이고 부드럽게 렌더링 하기 위한 컴포지터 스레드, 래스터 스레드를 실행하기도 합니다.

렌더링 엔진

  • 렌더링 엔진은 렌더러 프로세스의 한 요소입니다.

  • 렌더링 엔진은 HTML, XML, 이미지 등 요청 받은 내용을 브라우저 화면에 표시하는 엔진으로 각 브라우저마다 렌더링 엔진이 다르기 때문에 웹에서 CSS를 적용할 때 아래와 같이 접두어가 붙은 것을 종종 볼 수 있습니다.

    	-moz-border-radius: 1em; // 파이어폭스 브라우저에 적용
    	-ms-border-radius: 1em; // 익스플로어에 적용, 보통 생략
    	-o-border-radius: 1em; // 오페라에 적용
    	-webkit-border-radius: 1em; // 구글, 사파리 브라우저에 적용
  • 렌더링 엔진의 종류

    • Blink - 크롬, 오페라 
    • Webkit - 사파리
    • Gecko - 파이어폭스
    • Trident - 익스플로어
    • EdgeHTML - 마이크로소프트 엣지

Blink는 구글이 Webkit을 대체하기 위해 자체적으로 개발한 엔진입니다. 

렌더링 엔진 동작 과정

  • 웹 브라우저의 렌더링 과정을 Critical Rendering Path(CRP)라고 하며 서버로부터 응답받은 HTML 문서를 얻는 것으로 시작합니다. 이 문서의 내용은 보통 8KB 단위로 전송됩니다.
    • 렌더링 엔진은 HTML 문서를 파싱하여 DOM 트리를 생성합니다.
    • 렌더링 엔진이 스타일 태그를 만나면 CSS를 파싱하여 CSSOM 트리를 구축합니다.
    • DOM 트리와 CSSOM 트리를 합쳐 렌더 트리를 구축합니다.
    • 렌더 트리 각 노드에 대해 화면 상에서 배치할 곳을 결정합니다.
    • UI 백엔드에서 렌더 트리의 각 노드를 그립니다.

  • 위 그림은 렌더링 엔진 중 하나인 웹킷 엔진의 동작 과정을 그림으로 나타낸 것으로 위에서 설명한 기본 동작 과정과 유사합니다.
  • 페이지 초기 렌더링 이후 UI의 상태가 변경되어도 위 프로세스의 전체 혹은 일부를 거쳐 화면이 그려지게 됩니다. 따라서 CRP를 최적화하면 초기 컨텐츠를 화면에 빠르게 렌더링할 수 있을 뿐만 아니라 초기 렌더링 후 화면 업데이트 시간도 줄일 수 있습니다.

1) HTML 문서를 파싱하여 DOM(Document Object Model) 트리 구축

  • 파싱(parsing)은 브라우저가 코드를 이해하고 사용할 수 있는 구조로 변환하는 것을 의미합니다.
  • 파싱을 하기 위해선 모든 형식이 정해진 용어와 구문 규칙을 따라야하는데 HTML은 언어의 너그러운 속성HTML 오류에 대한 브라우저의 관용, 변경에 의한 재파싱으로 인해 정규 파서로 파싱할 수 없어 브라우저는 HTML 파싱을 위해 별도의 파서를 생성합니다.
  • HTML 파싱 과정은 크게 토큰화와 트리 생성 2단계로 이루어져있습니다.
    • 토큰화
      • 토큰화는 어휘 분석의 단위로서 입력값을 토큰으로 파싱합니다. HTML에서 토큰은 시작 태그, 종료 태그, 속성 이름과 속성값이 있고 토큰화에 의해 발행된 각 노드는 트리 생성자에 의해 트리에 추가됩니다.
    • 트리 생성
      • 파서가 생성되면 문서 객체가 생성됩니다. 트리 구축이 진행되는 동안 문서 최상단에는 DOM 트리가 수정되고 요소가 추가됩니다.
  • DOM은 마크업과 1:1 관계를 성립합니다.
<html>
  <body>
    <p>Hello World</p>
    <div><img src="example.png" /></div>
  </body>
</html>
  • 위와 같은 코드는 아래와 같은 DOM 트리로 변환할 수 있습니다.

2) CSSOM(CSS Object Model) 생성

  • CSS는 HTML과는 다르게 문맥 자유 문법으로 일반적인 파싱 기술을 사용할 수 있습니다.
  • 각 CSS 파일은 스타일 시트 객체로 파싱되고 각 객체는 CSS 규칙을 포함합니다. CSS 규칙 객체(CSSOM)는 선택자와 선언 객체 그리고 CSS 문법과 일치하는 다른 객체를 포함합니다.

3) 렌더 트리(DOM + CSSOM) 생성

  • DOM과 CSSOM을 합치는 작업을 어태치먼트(attachment)라고 하며, attachment의 결과로 렌더 트리가 생성됩니다. 렌더 트리는 문서를 시각적인 구성 요소로 만들어주는 역할을 합니다.
  • 웹킷은 이 구성 요소를 "렌더러(rendere)" 또는 "렌더 객체(render object)"라는 용어를 사용합니다. 렌더러는 자신과 자식 요소를 어떻게 배치하고 그려내야 하는지 알고 있습니다.
  • 렌더러는 DOM 요소에 부합하지만 1:1로 대응하는 관계는 아닙니다. 그 이유는 display: 'none'과 같은 사용자가 볼 수 없는 DOM 요소는 렌더 트리에 추가되지 않기 때문입니다.(visibilty 속성에 'hidden' 값이 할당된 요소는 트리에 나타납니다.)
* (좌) DOM 트리 (우) 렌더트리

4) 렌더 트리 레이아웃(배치)

  • 렌더 트리는 위치와 크기를 가지고 있지 않기 때문에 어는 공간에 위치해야 할지 각 객체들에게 위치(position)와 크기(size)를 결정해 주는데 이를 배치 또는 리플로라고 부릅니다.
  • 렌더러는 다시 배치할 필요가 있는 요소를 '더티'라고 표시해 소소한 변경 때문에 전체를 다시 배치하는걸 방지합니다.

5) 렌더 트리 페인팅(그리기)

  • 렌터 트리가 만들어져 레이아웃이 구성되었으면 UI 백엔드가 동작하여 렌더 트리의 각 객체를 화면의 픽셀(px)값으로 나타냅니다. 이 과정을 래스터 라이징이라고 하며 래스터 라이징은 그래픽 작업이므로 GPU의 도움을 받아 별도의 스레드에서 처리됩니다.(브라우저에 따라 CPU가 할 수도 있다)

6) 합성

  • 합성은 웹 페이지의 각 부분을 레이어로 분리해 별도로 래스터화하고 합치는 과정으로 컴포지터 스레드라고 하는 별도의 스레드에서 합성됩니다. 스크롤되었을 때 레이어는 이미 래스터화되어 있으므로 새 프레임을 합성하기만 하면 되고 애니메이션 역시 레이어를 움직이고 합성하는 방식으로 만들 수 있습니다.
  • 크롬 브라우저의 웹 페이지는 하나의 층이 아닌 여러 개의 레이어로 이루어져 있는데 화면이 여러 개의 레이어로 이루어져 있을 경우 화면의 어떤 요소의 CSS 속성이 변경되었을 때 전체가 변경되지 않고 해당 요소가 포함된 레이어만 변경, 합성하는 것으로 처리할 수 있는 장점이 있습니다.
  • 반면, 레이어가 너무 많으면 레이어를 저장하기 위한 메모리와 합성 작업을 위한 비용이 추가되므로 크롬은 레이어가 과도하게 많아지는 것을 막기 위해 경우에 따라 레이어를 생성하지 않기도 합니다.

위 과정을 렌더링 파이프라인이라고 부르며 1프레임마다 이 프로세스가 거듭된다고 보면 됩니다.(오늘날 대부분의 기기는 60프레임으로 작동) 렌더링 파이프라인에서 중요한 점은 각 단계에서 이전 작업의 결과가 새 데이터를 만드는데 사용된다는 점입니다.

여기서 성능을 최적화하기 위해서는 가급적 전체 파이프라인을 다시 호출하는 일을 적게 만들어야 합니다.

JS/CSS > 스타일 > 레이아웃 > 페인트 > 합성
레이아웃 너비, 높이, 왼쪽 또는 상단 위치 등 요소의 기하학적 형태에 영향을 주는 ‘layout’ 속성을 변경하면 브라우저가 다른 모든 요소를 확인하고 페이지에 대해 '리플로우’를 수행해야 합니다. 영향을 받은 영역이 있으면 다시 페인트해야 하고 최종적으로 페인트한 요소는 다시 합성해야 합니다.

JS/CSS > 스타일 > 페인트 > 합성
페이지의 레이아웃에 영향을 주지 않는 배경 이미지, 텍스트 색상 또는 그림자 등의 ‘paint only’ 속성을 변경하면, 브라우저가 레이아웃을 건너뛰되 페인트 작업은 여전히 수행합니다.

JS/CSS > 스타일 > 합성
레이아웃과 페인트가 필요 없는 속성을 변경하면 브라우저가 합성 단계로 건너뜁니다. 이 최종 버전은 앱의 수명 주기에서 애니메이션이나 스크롤처럼 많은 부담을 주는 시점에 가장 이상적이고 비용이 가장 적게 드는 버전입니다.

** 주어진 CSS 속성을 변경하는 위 세 가지 경우 중 어느 버전이 트리거될지 알고 싶은 경우 csstriggers.com 을 통해 어떤 속성 어떤 과정에 영향을 주는지 알 수 있습니다.


컴포지터가 사용자 입력을 받았을 때

  • 브라우저의 관점에서 입력이란 모든 사용자의 제스처를 의미합니다.
  • 화면 터치와 같은 사용자 제스처가 발생했을 때 가장 먼저 제스처를 수신하는 것은 브라우저 프로세스이지만 브라우저 프로세스는 제스처가 어디에서 발생했는지만 알고 있기 때문에 이벤트 유형과 이벤트가 발생한 좌표를 렌더러 프로세스로 보냅니다.
  • 렌더러 프로세스의 컴포지터 스레드는 입력 이벤트를 메인 스레드로 보내기 전 이벤트가 발생한 좌표에 무엇이 있는지 확인하기 위한 히트테스트(hit test)를 진행해 고속 스크롤 불가 영역 여부를 확인합니다.

    히트 테스트는 렌더러 프로세서에서 생성된 페인트 기록의 데이터를 사용합니다.

고속 스크롤 불가 영역

  • JavaScript 실행은 메인 스레드의 작업이므로 웹 페이지가 합성될 때 컴포지터 스레드는 이벤트 핸들러가 연결된 영역을 '고속 스크롤 불가 영역(non-fast scrollable region)'이라고 표시합니다.
  • 이 정보를 기준으로 해당 영역에서 이벤트가 발생했을 시 컴포지터 스레드가 메인 스레드로 입력 이벤트를 보낼지를 알 수 있습니다.
  • 입력 이벤트가 고속 스크롤 불가 영역 밖에서 발생했다면 컴포지터 스레드는 메인 스레드를 기다리지 않고 새 프레임을 합성합니다.

주의 사항

  • 웹 개발에서 이벤트를 처리하는 흔한 패턴으로 이벤트 위임이 있습니다. 하나의 이벤트 핸들러를 최상위 요소에 연결한 후 이벤트 대상을 고려해 처리를 위임할 수 있기 때문에 무척이나 편해 보이지만 브라우저 관점에서 보면 웹 페이지의 모든 영역이 고속 스크롤 불가 영역으로 표시됩니다.
  • 이렇게 되면 앱이 신경 쓰지 않는 부분에 입력이 들어와도 컴포지터 스레드는 들어오는 입력 이벤트마다 메인 스레드와 통신하고 처리가 끝날 때까지 기다리게 되어 컴포지터의 매끄러운 스크롤링 기능이 저하됩니다.
  • 이런 문제를 방지하기 위해 이벤트 리스너에 passive: true 옵션을 전달할 수 있습니다. 이 옵션은 여전히 메인 스레드에서 이벤트를 받지만 컴포지터가 메인 스레드의 처리를 기다리지 않고 새 프레임을 만들어도 된다는 힌트를 줍니다.

그렇다면 자바스크립트는?

  • 지금까지 설명으로 HTML 과 CSS를 렌더링 엔진에서 처리하는 과정을 알아봤습니다.
  • 사실 위 과정만으로도 브라우저에서 웹페이지를 화면에 나타내는 것은 충분합니다.
  • 그렇다면 자바스크립트가 하는 일은 무엇일까요? 자바스크립트는 HTML 태그를 동적으로 움직이게 만들어주는 역할을 하는 프로그래밍 언어입니다. 이 자바스크립트를 파싱하는 곳은 렌더링 엔진이 아닌 자바스크립트 엔진이 처리합니다.
  • HTML 파서는 <script> 태그를 만나면 JavaScript 코드를 실행하기 위해 DOM 생성 프로세스를 중지하고 자바스크립트 엔진으로 권한을 넘깁니다. 제어 권한을 넘겨받은 자바스크립트 엔진은 <script> 태그 내의 JavaScript 코드 또는 src 속성에 정의된 JavaScript 파일을 로드하고 파싱하여 실행합니다.
  • JavaScript의 실행이 완료되면 다시 HTML 파서로 제어권한을 넘겨서 중지했던 시점으로 돌아가 DOM 생성을 재개합니다.
  • 이를 통해 브라우저가 동기적이다는 것을 알 수 있습니다. 하지만 DOM이 완성되기 전에 스크립트가 DOM을 조작한다면 에러가 발생하기 때문에 script 태그를 body 태그 하단에 위치시킵니다.
  • 이 외에 제작자는 스크립트를 지연(defer)으로 표시할 수 있는데 지연으로 표시하게 되면 문서 파싱은 중단되지 않고 문서의 파싱이 완료된 이후에 스크립트가 실행됩니다.
  • HTML5는 스크립트를 비동기(asynchronous)로 처리하는 속성을 추가했기 때문에 별도의 맥락에 의해 파싱되고 실행됩니다.

head 태그 안에 위치

body 태그 아래 위치

defer

async

  
profile
코린이

0개의 댓글