면접 질문 정리

jm4293·2024년 2월 8일
1

마크업

  • 태그 들을 이용하여 문서나 데이터의 구조를 나타내는 방법이다

XML (Extensible Markup Language)

  • 마크업 형태를 쓰는 데이터 교환형식

HTML, XML 차이점

  1. HTML의 용도는 데이터를 표시 / XML은 데이터를 저장 및 전송
  2. HTML에는 미리 정의된 태그가 있지만 XML은 사용자가 고유한 태그를 만들고 정의 가능
  3. XML은 대/소문자를 구분하지만 HTML은 구분하지 않는다.

DOM

DOM의 개념을 설명해주세요

  • HTML이나 XML 같은 마크업 언어로 작성된 문서를 자바스크립트와 같은 프로그래밍 언어가 조작할 수 있도록 하는 인터페이스를 의미합니다. DOM은 계층적 구조를 가진 노드 트리로 구성됩니다.

DOM은 왜 필요한가요?

  • 동적인 웹 페이지를 구현하려면 자바스크립트와 같은 프로그래밍 언어가 문서에 접근하고, 제어할 수 있는 수단이 있어야 합니다. 하지만, 마크업 언어로 작성된 문서에는 이러한 수단이 없죠. TV는 있지만, TV를 조작할 수 있는 리모콘이 없는 것과 같은 이치라고 볼 수 있습니다. 따라서, 문서에 접근하고, 제어할 수 있는 수단인 DOM이 필요합니다.

DOM을 통해 어떤 동작을 할 수 있는지 예를 들어주세요

  • button element가 클릭되었을 때, 특정 함수를 호출하도록 Event Handler를 추가할 수 있고, 웹 페이지 내에 새로운 요소를 추가하거나, 삭제, 수정할 수 있습니다.

DOM은 왜 계층적 구조로 표현하는지 설명해주세요

  • 계층적 구조에서는 노드들 간의 관계가 부모, 자식, 형제 등으로 명확하게 정의됩니다. 이는 노드의 추가, 제거, 이동 작업을 쉽게 할 수 있도록 도와줍니다. 또한, 이벤트가 발생한 요소로부터 이벤트가 올라가는 이벤트 버블링, 반대로 이벤트가 내려가는 이벤트 캡처링 동작은 계층적 구조에서 효율적으로 동작하기 때문에, DOM을 계층적 구조로 표현하는 것입니다.

Promise, async, await

Promise의 개념에 대해 설명해주세요

  • Promise는 비동기 연산의 상태를 나타내는 객체입니다. 비동기 처리가 진행중이면 pending, 성공이면 fulfilled, 실패면 rejected라는 상태값을 가집니다. Promise는 비동기 프로그래밍을 then과 catch의 체이닝을 통해 보다 간결하게 표현할 수 있도록, ES6에서 새로 도입되었습니다.

Promise 등장 이전에는 어떤 방식으로 비동기 처리를 했는지 설명해주세요

  • Promise 등장 이전에는 비동기 작업을 처리하는 함수에 성공 콜백과, 실패 콜백을 각각 넘겨서 완료 상태에 따른 처리를 했습니다. 이런 방식이다 보니, 두 개 이상의 비동기 작업이 순서를 갖고 실행되어야 할 때, 콜백 함수 안에 또다른 콜백 함수가 점점 중첩되는 callback hell 현상이 발생하여, 코드 가독성 및 유지보수성 저하의 요인이 되곤 했습니다.

async-await에 대해 설명해주세요

  • Promise의 완료를 기다리기 위한 문법으로, async 키워드로 정의한 함수 내에서 호출되는 Promise 앞에 await 키워드를 쓰면, 해당 Promise가 완료될 때까지 코드의 실행을 일시정지할 수 있습니다. 이를 통해, 비동기 코드를 마치 동기 코드처럼 쉽게 작성할 수 있습니다.

async-await 를 사용할 때 주의해야할 점을 알려주세요

  • await의 에러 핸들링은 반드시 try-catch 블록에서 해야합니다. 또한, await는 Promise가 완료될 때까지 함수의 실행을 중단하기 때문에, 실행 흐름을 잘 고려하여 적재적소에 써야합니다. 예를 들어, 여러 비동기 작업이 순차적으로 진행될 필요가 없는 경우는, await 대신 Promise.all 함수를 사용하는 것이 바람직합니다.

React에서 key값

React에서 사용되는 key는 무엇인지 설명하세요

  • Key는 리스트를 매핑하여 동일한 컴포넌트를 여러 개 렌더링할 때 각 컴포넌트에 전달되는 고유한 값입니다. 재조정 단계에서 각 노드의 key 값들을 비교하여 리스트에 추가, 삭제, 혹은 순서가 변경된 노드를 식별하고, 이를 통해 필요한 re-rendering만 수행하기 위해 사용합니다.

배열의 index를 key값으로 하면 안되는 이유가 무엇인가요?

  • 배열의 인덱스를 key 값으로 사용하면 안 되는 이유는 순서가 변경되어도 동일한 key 값이 유지되기 때문입니다. A,B,C 순서로 rendering되어 있던 컴포넌트가 C,B,A 순서로 변경되어도 key값은 동일하기 때문에, 재조정 단계에서 re-rendering 대상으로 식별하지 않을 가능성이 생깁니다. 따라서, 배열 내에서 순서가 변경되어도 각 컴포넌트의 key값이 변경되지 않는 고유한 값으로 설정해야 합니다.

고유한 속성값을 주기 어려울 때는 어떤 값으로 대체할 수 있나요?

  • 컴포넌트에 전달되는 각 props를 적절히 조합하여 서로 겹치지 않는 id를 만드는 것이 효과적입니다. 이런 방식으로도 고유한 id를 할당하기 어려운 경우에는, 랜덤한 UUID를 생성하여 key값으로 전달할 수 있습니다. UUID는 128비트로 이루어져 있기 때문에, 서로 겹칠 가능성이 극히 적기 때문입니다. 하지만, UUID는 16바이트라는 비교적 큰 사이즈를 갖기 때문에, 메모리 공간을 효율적으로 사용할 수 없다는 단점이 있습니다.

이벤트 루프와 콜백

비동기 처리는 왜 필요한가?

  • 아시다시피, Javascript는 싱글 스레드 언어입니다. 그 말인 즉슨, 두 개 이상의 연산이나 함수를 동시에 실행할 수 없다는 뜻이죠. 하나의 연산이 실행 중이면, 쓰레드가 block되는 것입니다. 현대 컴퓨터 성능에서, 간단한 함수 실행에 의한 쓰레드 block은 체감하기 힘들지만, 네트워크 요청, DB Query, 파일 시스템 제어 등 시간이 오래 걸리는 작업도 있습니다. 이런 작업들이 메인 쓰레드를 block하고 있으면, 심각한 자원 낭비와 사용성 저하로 이어질 수 있겠죠. 따라서, 메인 쓰레드를 block하지 않고 이런 작업들을 수행할 수 있는 방안이 필요합니다.

비동기 작업이란 무엇인가?

  • 다행히 자바스크립트 엔진은, 긴 시간이 소요되는 작업들을 메인 쓰레드에서 처리하지 않습니다. Node.js의 경우, libuv라는 C++ 라이브러리를 통해, 브라우저의 경우 Fetch와 같은 웹 API를 통해 백그라운드에서 처리하죠. 이렇게 자바스크립트의 메인 쓰레드가 아닌, 백그라운드에서 처리하는 작업을 "비동기 작업"이라고 부르는 것입니다.

왜 C++ 라이브러리를 사용하는가?

  • 그럼 여기서 한 가지 의문이 들 수 있죠. 백그라운드라는 것은 무엇이며, 왜 자바스크립트를 실행하는데 C++ 라이브러리를 사용하는가? 이를 이해하기 위해선, "자바스크립트"와 "자바스크립트 실행 환경"을 구분하는 것이 중요합니다. "자바스크립트 실행 환경"인 Nodejs와 브라우저는 자바스크립트만으로 이루어져 있지 않습니다. 자바스크립트만으로 프로그램의 기본적인 흐름은 잡을 수 있지만, 한계가 있기 때문이죠. 여기에는 single thread blocking 이슈를 비롯하여, 파일 시스템 접근과 OS 수준의 작업이 자바스크립트만으로는 불가능하다는 문제도 있습니다. 이 한계를 보완하기 위하여 자바스크립트 실행 환경 내에 자바스크립트로 접근 가능한 여러 기능들을 구현해 놓은 것입니다. 비동기 처리도 이 기능들 중 하나구요. 집에 TV나 냉장고가 없다고 해서 사람이 살 수 없는 것은 아니지만, 있으면 삶의 질이 확실히 올라가죠? 여기서 자바스크립트의 메인 쓰레드를 사람에, libuv와 웹 API를 가전 제품에 비유해볼 수 있습니다.

Callback 함수란 무엇인가?

  • 다시 본론으로 돌아와, 메인 쓰레드에서 "비동기 함수"를 만나면 실제 처리를 백그라운드로 위임한다고 설명드렸습니다. 당연하게도, 백그라운드에서 작업이 완료되면, 실패가 됐든, 성공이 됐든 메인 쓰레드가 결과를 알 수 있어야합니다. 왜냐하면 메인 쓰레드에서 요청한 작업이니까요. 동시에, 메인 쓰레드 입장에서 비동기 작업이 성공했을 때는 이런 처리를, 실패했을 때는 저런 처리를 하고 싶다는 요구가 있을 수 있습니다. 그래서 우리는 비동기 함수를 호출할 때, 처리 완료 시 메인 쓰레드에서 실행할 함수를 함께 전달하는데, 이를 callback함수라고 합니다. 웬만한 비동기 함수들은 callback 함수를 인자로 받을 수 있게 설계되어 있고, 보통 마지막 인자로 전달하게끔 되어있으니, 각 함수별 스펙을 참고하시면 되겠습니다. 정리하자면, "비동기 작업이 완료되었을 때 메인 쓰레드에서 실행할 함수"를 callback 함수라고 부른다는 것입니다.

이벤트 루프의 필요성

  • callback 함수는 백그라운드로 잠시 전출간 메인 쓰레드 식구입니다. 즉, 언젠가는 다시 메인 쓰레드 안으로 들어와야 한다는 것이죠. 그런데, 메인 쓰레드와 백그라운드는 별도의 프로세스이기 때문에, callback함수가 들어와야 하는 시점이 애매해질 수 있습니다. 메인 쓰레드에서 다른 연산이 진행 중일 수 있기 때문인데요, 따라서, 이 callback함수가 들어올 시점을 정해주는 체계가 필요하며, 이 역할을 담당하는 것이 바로 Event loop입니다.

Event Loop의 동작 원리

  • 메인 쓰레드에서 실행되는 모든 함수들은 Call Stack이라는 공간에 LIFO 형태로 차곡차곡 쌓이게 됩니다. 함수가 호출되면 Call Stack에 push되고, return 문을 만나면 pop되는 단순한 구조이죠. 만약 Call Stack에 비동기 함수가 들어오면 즉시 pop하여 백그라운드로 전달합니다. 비동기 함수가 백그라운드에서 처리되는 한편, 동시에 Call Stack에서는 다음 함수가 계속해서 실행되고 있기 때문에 single thread blocking 문제를 해결할 수 있습니다. 이후, 백그라운드에서 비동기 처리가 완료되면, 호출 시점에 전달한 callback함수가 Event Queue라는 공간에 FIFO 구조로 쌓이게 됩니다. 여기서 이벤트 루프가 등장하는데, 간단히 말하자면 Event Queue에서 Call Stack으로 callback 함수를 이동시켜주는 역할을 합니다. 이벤트 루프는 call stack이 완전히 비어있는지 수시로 확인하며, 비어있는 경우 event queue에서 callback함수를 shift한 다음, call stack에 push해주는 역할을 수행합니다. Event Queue와 Call Stack 사이에 존재하는 일종의 신호등이죠.
  1. 모든 함수 호출들은 call stack에 LIFO구조로 쌓인다.
  2. 비동기 함수는 Call stack에 들어오는 즉시 백그라운드로 보내진다.
  3. 백그라운드에서 처리가 완료되면 callback 함수들은 event queue에 FIFO구조로 쌓인다. 1. Event Loop는 Call Stack이 비었는지 수시로 확인한다.
  4. Call Stack이 비어있을 경우, Event Loop는 Event queue에서 callback 함수를 shift한다.
  5. shift 된 Callback 함수는 Call stack으로 옮겨진 후 실행한다.

리플로우와 리페인트

리플로우란 무엇인지 설명해주세요

  • 리플로우란, 웹 페이지 내에서 요소의 위치 또는 크기에 변화가 있을 때, 변화된 레이아웃을 다시 계산하여 렌더 트리에 적용하는 과정을 의미합니다. width, height, padding, margin 그리고 border-width와 같은 크기 관련 속성, position, top, left와 같은 위치 관련 속성, display, flex 속성과 같은 레이아웃 관련 속성, font-size, font-weight와 같은 폰트 크기 관련 속성이 리플로우를 유발하는 속성입니다.

리페인트란 무엇인지 설명해주세요

  • 리페인트란, 웹 페이지 내에서 요소의 시각적인 표현에 변화가 있을 때, 변화된 시각적 표현을 다시 계산하여 렌더 트리에 적용하는 과정을 의미합니다. color, background-color 같은 색상 관련 속성, border-color, border-radius 와 같은 테두리 관련 속성이 리페인트를 유발하는 속성입니다.

리플로우와 리페인트의 성능상 차이점을 설명해주세요

  • 부모 노드의 레이아웃 변화는 자식 노드의 레이아웃까지 영향을 미치기 때문에, 리페인트와는 달리, 리플로우가 발생하면 하위 렌더 트리를 다시 계산하고 재구성하는 과정이 필요합니다. 따라서, 리플로우는 그 자체만으로도 부하가 큰 작업입니다. 또한, 리플로우가 발생하면 일반적으로 리페인트도 다시 발생하기 때문에, 성능에 큰 영향을 끼친다고 할 수 있으며, 렌더링 성능을 최적화하기 위해선 리플로우를 최소화해야 합니다. 또한, 리플로우는 주로 CPU를 활용하여 연산하는 반면, 리페인트는 GPU를 활용한다는 차이도 있습니다.

리플로우를 최소화하기 위한 방법은 무엇이 있을까요?

  • 리플로우를 최소화하기 위해, DOM 업데이트를 하나로 묶어 Batch Update하는 방법을 생각해볼 수 있습니다. 또한, offsetHeight, offsetWidth와 같은 자바스크립트의 레이아웃 속성에 여러 번 접근하면 리플로우가 발생할 수 있기 때문에, 이러한 속성들은 변수에 저장해 두고 재사용해야 합니다. 마지막으로, 가급적 레이아웃 변경이 적은 요소를 사용해야 합니다. position 속성을 예로 들면 fixed나 absolute 같은 값들을 사용할 수 있습니다.

Virtual Dom

Virtual DOM의 개념에 대해 설명하세요

  • Virtual DOM은 웹 성능을 최적화하기 위해 사용되는 DOM 관리 방법으로, 웹 어플리케이션의 상태 변경 시, 객체 형태의 가상 DOM을 통해 변경된 부분만 찾아내어 이를 실제 DOM에 적용하는 기능을 합니다. Virtual DOM의 동작 순서는 Diffing과 Reconiliation, 크게 두 가지로 구분할 수 있는데, Diffing이란, Virtual DOM에서 변경점을 찾아내는 과정을 의미하며, Reconciliation이란, 찾아낸 변경점을 실제 DOM에 적용하는 과정을 의미합니다.

Virtual DOM이 동작하는 예시를 간략히 설명해주세요

  • 먼저, 어플리케이션이 제일 처음 rendering 될 때, 어플리케이션의 초기 상태를 담은 Virtual DOM을 메모리 상에 하나 생성합니다. 이후, 어플리케이션이 실행되면서 state나 props가 변경된 부분이 있는 경우, 새로운 버전의 Virtual DOM을 메모리 상에 하나 더 생성합니다. 새로운 버전의 Virtual DOM이 생성된 후, 이전 버전의 Virtual DOM과 비교하는 과정인 Diffing에 돌입하고, 변경점을 찾아냅니다. 이 과정에서 두 Virtual DOM 트리의 각 노드를 비교하여 어떤 부분이 변경되었는지 확인합니다. 변경점을 찾아낸 이후에는, 실제 DOM에 적용하는 과정인 Reconciliation에 돌입합니다. 이 과정에서 변경된 부분만 실제 DOM에 업데이트하기 때문에, 브라우저 성능이 향상될 수 있는 것입니다. Reconciliation이 완료된 이후, 또 다른 변경점이 생기면, 구 버전의 Virtual DOM이 폐기되고, 새로운 변경 사항을 반영한 최신 버전의 Virtual DOM이 다시 생성됩니다.

그럼 state나 props가 변경될 때마다 Diffing과 Reconciliation이 수행되는건가요?

  • React를 비롯하여 Virtual DOM을 사용하는 대부분의 프레임워크에서는 Batch 업데이트를 지원하고 있습니다. 따라서, 짧은 시간 안에 여러 개의 state와 props가 동시에 변경되면, 이를 각각 처리하는 것이 아니라, 한꺼번에 모아서 처리합니다.

Virtual DOM을 사용하는 것이 그렇지 않은 것보다 좋은가요?

  • 항상 그런 것은 아닙니다. 간단한 어플리케이션의 경우에는 Virtual DOM을 사용하는 것이 오히려 오버헤드를 초래할 수 있습니다. 왜냐하면 Virtual DOM 자체도 메모리 공간을 차지하고, Diffing하는 과정 역시 CPU를 활용하기 때문입니다. 다만, DOM 트리가 복잡하고, 상태 변경도 빈번하게 일어나는 대규모 어플리케이션에서 사람의 인지 능력으로는 정확히 어떤 DOM을 업데이트해야 하는지 식별하기 어렵기 때문에, Virtual DOM을 사용하는 것입니다. 따라서, 어플리케이션의 복잡도와 요구 사항에 맞게 Virtual DOM 적용 여부를 결정하는 것이 좋습니다.

자바스크립트 호이스팅

호이스팅이란 무엇인지 설명해주세요

  • 호이스팅이란, 변수와 함수의 선언문이 해당 스코프의 최상단으로 끌어올려지는 현상을 의미합니다. 이러한 현상으로 변수와 함수가 초기화되기 전에 접근할 수 있는 현상이 발생합니다. 단, ES6에서 등장한 방식인 let과 const로 선언한 변수들은 호이스팅은 되지만, 초기화 전에 접근할 수는 없습니다.

변수와 함수 모두 호이스팅이 동일하게 동작하나요?

  • 아닙니다. 변수는 선언만 호이스팅 되지만, 함수는 선언과 초기화 모두 호이스팅됩니다. 이러한 특성으로 인해, 변수는 초기화 전에 참조할 경우, undefined가 나오지만, 함수는 초기화 전에 호출해도 정상적으로 호출이 가능합니다.

왜 변수와 달리, 함수만 초기화 과정까지 호이스팅 되나요?

  • function 키워드로 선언한 함수는 선언과 초기화, 할당 단계가 내부적으로 동시에 진행되기 때문입니다. 반면, 변수는 선언과 초기화를 한 구문으로 코딩했어도, 내부적으로는 두 단계에 걸쳐서 실행됩니다.

왜 let과 const으로 선언한 변수는 초기화 전에 접근할 수 없도록 막아 놓았나요?

  • 호이스팅 현상으로 인해, 초기화되지 않은 변수를 개발자가 참조할 수 없도록 하기 위해서입니다. 즉, 코드의 예측 가능성을 높이기 위해 Temporal Dead Zone (TDZ) 이라는 개념을 도입한 것입니다. 또한, 자바스크립트의 창시자인 브랜든 아이크에 따르면, 호이스팅 현상은 자바스크립트 개발 과정에서 실수로 생긴, 일종의 버그이기 때문에, 이를 ES6 버전에서 해결한 것으로 보입니다.

자바스크립트는 인터프리터 언어인데, 어떻게 호이스팅 현상이 일어날 수 있는건가요?

  • 일반적으로 알고 있는 인터프리터의 개념과는 달리, 자바스크립트 엔진은 코드 실행을 위해 파싱과 실행이라는 두 단계를 거치게 됩니다. 호이스팅이 처리되는 파싱 단계에서는 호이스팅 뿐만 아니라, 구문 트리와 실행 컨텍스트를 생성하는 작업도 함께 수행됩니다.

화살표 함수와 function 키워드의 차이점

화살표 함수와 function 키워드의 차이점을 설명해주세요

  • 먼저, 화살표 함수는 코드 블럭을 사용하지 않을 경우, return 문을 명시할 필요가 없습니다. 또한, function 키워드는 arguments 객체를 통해 함수 인자에 접근할 수 있지만, 화살표 함수는 arguments 객체를 갖지 않기 때문에, 나머지 매개 변수를 통해 함수 인자에 접근할 수 있습니다. 마지막으로, 함수 호출 방식에 따라 this의 참조가 다르게 동작하는 function 키워드와는 달리, 화살표 함수는 this가 항상 상위 스코프의 this를 참조합니다.

왜 화살표 함수에서는 this가 항상 상위 스코프를 참조하도록 하였을까요?

  • function 키워드로 정의한 함수는 호출 방식에 따라 this 바인딩이 다르게 동작하기 때문에, this 값을 예측하기 어렵다는 문제가 있습니다. 따라서, 화살표 함수에서는 this가 항상 상위 스코프를 참조하도록 개선하여, this 바인딩의 일관된 동작을 보장하고, 코드 흐름에 따라 this의 참조값을 예측하기 쉽도록 만든 것입니다.

function 키워드 함수의 this 바인딩은 어떤 식으로 동작하나요?

  • 일반적인 함수 호출의 경우는 this가 전역 객체를 가리키며, 객체의 메서드로 호출되는 경우는 해당 객체를 가리키게 됩니다. 또한, 함수가 이벤트 핸들러로써 호출되는 경우에는 이벤트가 발생한 요소를 가리킵니다. 이처럼, function 키워드로 정의한 함수는 this 바인딩의 일관성이 부족하기 때문에, ES6 이전에는 apply나 call, bind와 같은 함수를 통해 명시적으로 this 바인딩을 수행했습니다.

렉시컬 스코프

스코프란 무엇이며, 자바스크립트의 스코프는 어떻게 동작하나요?

  • 스코프란, 변수나 함수의 유효 범위를 의미합니다. 즉, 특정 변수나 함수를 어느 위치에서 참조할 수 있는 지를 나타내며, 만약 스코프에서 벗어난 위치에서 참조할 경우 Reference Error가 발생합니다. 자바스크립트의 스코프는 크게 전역 스코프와 로컬 스코프로 나눌 수 있으며, 이들 모두 렉시컬 스코프 규칙에 따라 결정됩니다. 로컬 스코프는 다시 함수 스코프와 코드 블록 스코프로 나눌 수 있는데, let과 const로 정의한 변수만 코드 블록 스코프를 가질 수 있습니다.

렉시컬 스코프란 무엇인가요?

  • 렉시컬 스코프란, 변수가 어디에 정의되었는지에 따라 스코프가 결정되는 메커니즘을 의미하며, 정적 스코프라고 부르기도 합니다. 이는 코드가 작성된 위치에 따라 변수의 유효 범위가 결정된다는 뜻입니다. 이러한 이유로, 서로 독립적인 로컬 스코프 A, B가 있을 때, A 내부에 선언된 변수를 B 위치에서, B 내부에 선언된 변수를 A 위치에서 참조할 수 없습니다. (단, 이 때 각 변수는 전역 변수에도 선언되어 있지 않다고 가정) 또한, 함수가 중첩된 경우 내부 함수는 외부 함수의 변수를 참조할 수 있지만, 외부 함수는 내부 함수의 변수를 참조할 수 없습니다.

자바스크립트에서 변수를 참조하는 과정을 설명해주세요

  • 자바스크립트는 함수가 실행될 때마다 메모리 상에 실행 컨텍스트를 생성합니다. 이 실행 컨텍스트 안에는 렉시컬 환경이 존재하는데, 여기에 현재 스코프에서 선언한 모든 변수와 함수들이 저장되어 있는 환경 레코드가 존재합니다. 또한, 현재 환경에서 찾지 못한 변수를 상위 스코프에서 찾기 위해, 상위 스코프를 가리키는 외부 렉시컬 환경 참조도 갖고 있죠. 이를 통해, 코드 상에서 변수나 함수를 참조하면, 먼저 현재의 환경 레코드에서 찾아보고, 없을 경우 외부 렉시컬 환경 참조를 통해 상위 스코프를 참조하게 됩니다. 이런 식으로 모든 상위 스코프를 탐색했는데도 찾지 못할 경우, 전역 스코프까지 올라가며, 여기서도 찾지 못하면 Reference Error를 발생시킵니다.

브라우저 렌더링 과정

브라우저 렌더링의 순서를 설명해주세요

  • 먼저 서버로부터 HTML 문서를 전달받으면, 브라우저 엔진은 위에서 아래로 순차적으로 파싱하며 태그와 속성을 발견합니다. 이 태그와 속성들은 트리 형태로 변환되어 메모리에 저장되는데, 이를 DOM 트리라고 합니다. HTML 파싱 중 CSS 링크 또는 스타일 태그를 만나면, 이를 파싱하여 CSSOM 트리로 변환합니다. 문서의 파싱이 완료되면, DOM과 CSSOM 트리를 결합하여 렌더 트리를 생성합니다. 렌더 트리는 브라우저 상에서 요소의 위치와 크기를 결정하는 리플로우 과정을 거치며, 마지막으로 요소의 색상, 경계선 등 시각적 요소를 그리는 페인팅 과정이 진행됩니다.

HTML 파싱 중간에 script 태그를 만나면 어떻게 되나요?

  • 파싱 중간에 script 태그를 만나면, 브라우저는 해당 스크립트를 로드하고 실행하기 위해 파싱을 일시 중단합니다. 외부 스크립트의 경우, 스크립트를 로드하고 실행한 후 파싱을 재개하며, 내부 스크립트의 경우, 실행이 완료될 때까지 파싱이 중단됩니다. 이로 인해 파싱 속도가 저하되고, DOM 트리가 완성되기 전에 스크립트가 DOM을 조작할 가능성이 있어, 예기치 못한 상황이 발생할 수 있습니다. 이러한 문제를 방지하기 위해 asyncdefer 속성을 사용하여 파싱에 미치는 영향을 최소화할 수 있습니다.

async와 defer 속성에 대해 설명해주세요

  • asyncdefer는 스크립트를 비동기적으로 로드하는 속성입니다. 이들은 HTML 파싱이 중단되는 현상과 DOM 트리가 완성되기 전에 스크립트가 실행되는 것을 방지하기 위해 사용됩니다. async 속성은 스크립트가 로드되는 즉시 실행하는 반면, defer 속성은 스크립트를 비동기적으로 로드하되, HTML 파싱이 완료된 후 스크립트를 실행합니다. 따라서 async는 스크립트 로드 순서 상관없이 실행되는 경우에 적합하고, defer는 스크립트의 실행 순서가 중요할 때 적합합니다.

profile
무언가를 만드는 것을 좋아합니다

0개의 댓글

관련 채용 정보