브라우저의 렌더링 과정에 대해 설명해보세요
주소창에 URL을 입력하고 엔터키를 누르면 DNS를 통해 IP 주소로 변환
이 IP 주소를 갖는 서버에게 요청을 전송 (HTML, CSS, JS, 이미지, 폰트 파일 등 렌더링에 필요한 리소스를 요청)하고 서버로부터 응답을 받는다.
브라우저의 렌더링 엔진은 서버로부터 응답한 HTML과 CSS를 파싱하여 DOM과 CSSOM을 생성하고 이들을 결합하여 렌더 트리를 생성한다. (바이트 > 문자 > 토큰 > 노드 > DOM 또는 CSSOM)
브라우저의 자바스크립트 엔진은 서버로부터 응답된 자바스크립트를 파싱하여 AST(Abstract Syntax Tree)를 생성하고 바이트코드로 변환하여 실행한다. 이때 자바스크립트는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 있다. 변경된 DOM과 CSSOM은 다시 렌더 트리로 결합된다.
렌더 트리를 기반으로 HTML 요소의 레이아웃(위치와 크기)을 계산하고 브라우저 화면에 HTML 요소를 페인팅(화면에 픽셀 렌더링)한다.
브라우저의 렌더링 과정에 자바스크립트는 어떻게 동작하나요?
<script></script>
태그를 만나면 DOM 생성을 일시 중단
JS 파일을 서버에 요청해 로드한 JS 파일이나 script
태그 내의 JS 코드를 파싱하기 위해 JS 엔진에 제어권 넘김 (자바스크립트의 파싱과 실행은 브라우저 렌더링 엔진이 아닌 자바스크립트 엔진이 처리)
JS 엔진은 자바스크립트를 해석하여 AST(추상적 구문 트리)를 생성
AST를 기반으로 인터프리터가 실행할 수 있는 중간 코드인 바이트코드 생성해 실행
JS 소스코드 → 토큰 → AST → 바이트코드
<script></script>
태그를 <body></body>
태그 밑에 둬야하는 이유가 있을까요?
렌더링 엔진과 자바스크립트 엔진은 병렬적으로 파싱을 실행하지 않고 직렬적으로 수행하기 때문이다.
브라우저는 위에서 아래 방향으로 순차적으로 HTML, CSS, JS를 파싱하고 실행
script 태그 위치에 따라 HTML 파싱이 블로킹되어 DOM 생성이 지연될 수 있다
DOM 생성이 지연된 상태에서 DOM을 조작하는 경우 문제가 발생
<script></script>
태그를 <body></body>
태그 밑에 뒀을 때 자바스크립트 로딩/파싱/실행으로 인해 HTML 요소들의 렌더링에 지장받는 일이 발생하지 X → 페이지 로딩 시간 단축
async
와 defer
어트리뷰트
async
script
태그에 async
를 지정하면 script
태그 순서와는 상관없이 로드가 완료된 자바스크립트부터 먼저 실행되므로 순서가 보장Xdefer
DOM이 뭔가요?
DOM을 구성하는 건 뭐가 있나요?
HTML 요소는 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 요소 노드 객체로 변환
HTML 요소 어트리뷰트는 어트리뷰트 노드로, HTML 요소의 텍스트 콘텐츠는 텍스트 노드로 변환된다.
DOM은 노드 객체의 계층적인 구조로 구성
mouseup으로 대체
이벤트 타입 | 이벤트 발생 시점 |
---|---|
click | 마우스 버튼 클릭 |
dblclick | 마우스 버튼 더블 클릭 |
mousedown | 마우스 버튼을 눌렀을 때 |
mouseup | 누르고 있던 마우스 버튼을 놓았을 때 |
mousemove | 마우스 커서를 움직였을 때 |
mouseenter | 마우스 커서를 HTML 요소 안으로 이동했을 때 (버블링 X) |
mouseover | 마우스 커서를 HTML 요소 안으로 이동했을 때 (버블링 O) |
mouseleave | 마우스 커서를 HTML 요소 밖으로 이동했을 때 (버블링 X) |
mouseout | 마우스 커서를 HTML 요소 밖으로 이동했을 때 (버블링 O) |
그 외에 알고 있는 대표적인 이벤트가 있나요?
이벤트 타입 | 이벤트 발생 시점 |
---|---|
keydown | 모든 키를 눌렀을 때 발생 |
focus | HTML 요소가 포커스 받았을 때 (버블링 X) |
blur | HTML 요소가 포커스 잃었을 때 (버블링 X) |
submit | 1. form 요소 내의 input, select 입력 필드에서 엔터키 눌렀을 때 |
2. form 요소 내의 submit 버튼을 클릭했을 때 | |
scroll | 웹페이지 또는 HTML 요소를 스크롤할 때 연속적으로 발생 |
input | input, select, textarea 요소의 값이 입력되었을 때 |
이벤트 핸들러를 등록하는 방식에는 어떤 것들이 있나요?
이벤트 핸들러 어트리뷰트
HTML 요소의 이벤트 핸들러 어트리뷰트를 할당
이벤트 핸들러 프로퍼티
이벤트 타깃의 이벤트 핸들러 프로퍼티에 함수를 바인딩
addEventListener 메서드 방식
이벤트 타깃의 addEventListener 메서드 사용 (이벤트타입, 이벤트핸들러, capture 사용 여부)
이벤트 전파(propagation)에 대해서 알고 있나요?
이벤트 위임(delegation)에 대해서 알고있나요?
e.preventDefault 에 대해 알고 있나요?
e.stopPropagation
호출 스케쥴링이 무엇인가요?
타이머 함수에는 어떤 것들이 있나요?
setTimeout / clearTimeout
두번째 인수로 전달받은 시간 이후 첫번째 인수로 전달받은 콜백 함수가 호출 (단 한번 실행)
const timeoutId = setTimeout(func|code[, delay, param1, param2, ...]);
clearTimeout(timeoutId);
setTimeout 함수는 생성된 타이머를 식별할 수 있는 고유한 타이머 id 반환 (브라우저 : 숫자 , Node.js : 객체)
반환한 타이머 id를 clearTimeout의 인수로 전달해 타이머 취소 가능
setInterval / clearInterval
두번째 인수로 전달 받은 시간이 경과할 때마다 첫번째 인수로 전달받은 콜백 함수가 반복 호출
const timeoutId= setInterval(func|code[, delay, param1, param2, ...]);
clearInterval(timeoutId);
이벤트가 과도하게 호출되어 성능에 문제를 일으킬 경우에 할 수 있는 어떤 일을 통해 해결할 수 있나요?
디바운스에 대해서 알고 있나요?
쓰로틀에 대해서 알고 있나요?
동기와 비동기의 차이점에 대해서 설명해줄 수 있나요?
이벤트 루프와 태스크 큐에 대해서 알고 있나요?
이벤트 루프
태스크 큐
function foo(){
console.log("foo");
}
function bar(){
console.log("bar");
}
setTimeout(foo, 0);
bar();
전역 코드가 평가되어 전역 실행 컨텍스트가 생성되고 콜 스택에 푸시
전역 코드 실행되기 시작하여 setTimeout 함수 호출. 이때 setTimeout 함수의 함수 실행 컨텍스트가 생성되고 콜스택에 푸시되어 현재 실행중인 실행컨텍스트가 된다.
setTimeout 함수가 실행되면 콜백 함수를 호출 스케줄링하고 종료되어 콜 스택에서 팝
브라우저가 수행하는 4-1과 JS 엔진이 수행하는 4-2는 병행처리
4-1. 브라우저는 타이머를 설정하고 타이머 만료를 기다린다. 이후 타이머가 만료되면 콜백 함수 foo가 태스크 큐에 푸시. setTimeout 함수로 호출 스케줄링한 콜백 함수는 정확히 지연시간 후에 호출된다는 보장은 없다. 태스크 큐에 푸시되어 대기하지만 콜 스택이 비어야 호출하기 때문에 약간의 시간차 발생 가능
4-2. bar 함수가 호출되어 bar 함수의 함수 실행컨텍스트가 생성되고 콜스택에 푸시되어 현재 실행중인 실행 컨텍스트가 된다. 이후 bar 함수가 종료되어 콜스택에서 팝
전역 코드 실행 종료 및 콜스택에서 팝
이벤트 루프에 의해 콜 스택이 비어있음이 감지되고 태스크 큐에서 대기중인 콜백 함수 foo가 이벤트 루프에 의해 콜스택에 푸시, 실행 후 팝
마이크로태스크 큐에 대해서 알고 있나요?
태스크 큐와 마이크로태스크 큐 중 어떤 것이 먼저 실행되나요?
setTimeout(() => console.log(1), 0);
Promise.resolve()
.then(() => console.log(2))
.then(() => console.log(3));
// 2 3 1