코타키나발루 사피섬

해당 포스트는 하루에 하나씩 FE 개발자 면접 문제 오픈 채팅방에서 매일 출제되는 퀴즈를 토대로 학습 및 토론내용을 정리한 게시글입니다.

1. Quiz 및 답변

퀴즈

안녕하세요~ 좋은 하루입니다! 오늘의 FE의 질문은!!

가상 DOM의 동작 원리를 설명하고, 실제 DOM과의 차이점을 설명해 주세요. 또한, Virtual DOM을 사용하는 React의 렌더링 성능 최적화 방식에 대해 설명하고, shouldComponentUpdate 또는 React.memo와 같은 기법이 어떤 역할을 하는지 설명하세요.

답변

 가상 DOM은 DOM의 업데이트 비용을 줄이기 위해 설계되었으며, 실제 DOM의 구조를 메모리에 경량화시킨 객체로 표현한 것입니다.
리액트는 상태변경이 일어나면 가상 DOM을 생성해 이전 가상 DOM과 비교하여 실제DOM에 필요한 최소한의 업데이트만 수행하는 방식으로 렌더링 비용을 최소화 합니다.

 React.memo는 리액트에서 props가 동일함에도 리렌더링 계산이 일어나는 비용을 방지하기 위해 고안되었으며, 컴포넌트의 props를 메모해 이전값과 같다면 리렌더링 계산을 일으키지 않도록 설계하였습니다.

2. 토론

일치하는 답변은 가상 DOM은 DOM 조작 비용을 최소화 시켜준다! 와 React.memo는 불필요한 리렌더링을 방지하는 최적화 기법이다! 의 내용이였습니다.

관련하여 다양한 이야기가 오고갔고, 대표적인 몇가지 사례만 공유하겠습니다.

 

Q.1 '🤔  대체 불필요한 리렌더링이랑 무엇일까..'

대체 불필요한 리렌더링이랑 무엇일까.. 애니메이션 아니면 딱히 보이지도 않지 않나 라는 의문이 생겨요!
리액트 성능최적화는 "불필요한 리렌더링을 피하라"가 아니라 초당 16ms 안에 모든 계산을 끝내라가 핵심인거 같아요. 결국 리액트 씀으로써 버벅거리는건 초당 60프레임을 유지 못하기 때문이라서 그렇다고 생각하는데.. 이 부분에 대해서 어떻게 생각하시나요 여러분?

 

 

FE 토론방의 장점같은 질문이 나왔습니다.!

 사담을 펼치자면 저는 요즘들어 깊게 고민하지 않고 타인이 알려주는 해설지를 가지고 개발하는 경우가 많아졌어요.. 교보재나 강의, AI등의 조언을 듣고 가장 이상적인 방법을 선택하는거죠! 이전보다 혁신적으로 개발이 편해졌지만 이전처럼 한 가지 문제를 가지고 더 나은 방향성은 무엇일까? 고민하는 시간들이 줄어든것 같아요! 그 점에서 위와같은 질문은 오랜만에 느껴보는 고민이였어요!

 

[사고의 맥락]
  불필요한 렌더링을 어떤 관점에서 보고 계실까.. 맥락상 1프레임안에 다발적으로 일어나는 렌더링까지 최소화할 필요가 있나? 라는 관점에서 이야기를 하신것 같습니다. 저도 무의식적으로 모든 최적화를 자연스럽게 진행하지만 이것또한 비용이기 때문에 위와같은 고민은 공감이 갔습니다.

'왜 나는 무의식적으로 모든 최적화를 진행하였을까? 그렇다면 최적화를 후순위로 미루어볼까?''


 위와 같은 생각을 하자마자 든 결론은 미리 하는게 낫다! 라는 결론이 였습니다. 아래와 같은 고민들을 하게 되었습니다.

 

1프레임 안에 리렌더링 되는 컴포넌트 기준을 무엇으로 할까?
확장성이 올라가서 여러 컴포넌트끼리 묶였을때는 최적화를 진행해야겠다!


슬슬 머리가 복잡해 지는 시점에 다시금 내린 결론은 아래와 같습니다.

 

'최적화를 하면서 개발하는 비용보다, 할지 말지를 고려하는 비용이 더 큰 것 같다!'

 

 

[당시 답변]

 

 저는 '안해도 될 것을 왜 해야하는가?' 에 초점을 맞추어 대답을 진행하였습니다. 당연히 하는게 좋지만 안해도 문제가 없으면 굳이 안해도 되는 부분을 수용하였고, 하지만 그때 고려해야 할 비용이 하는것 보다 크다면 하는게 나을 것 같다라는 의견을 제시하였습니다.


 

3. 후기

 

 이전에 리액트를 공부할때 'React.memo 는 리렌더링을 방지한다' 라는 관점에서 가상DOM이 있으면 실제DOM에 리렌더링되지 않을텐데 왜 React.memo가 없으면 리렌더링을 일으킨다 하는거지? 와 같이 실제DOM부분에서 리렌더링이 없는데 그러면 'React.memo 는 리렌더링을 방지한다' 라는 표현은 틀린게 아닐까? 와 같은 생각을 했었습니다.

 

 결과적으로 React.memo는 실제 DOM이 아닌 가상 DOM 수준에서의 렌더링을 방지하는것이였습니다! React.memo는 컴포넌트의 props가 변경되지 않았을 때 가상 DOM에서의 렌더링 계산을 건너뛰게 하여, 불필요한 가상 DOM 업데이트를 방지하였습니다.

 

리액트의 렌더링 최적화가 가상 DOM에서 이루어지고, 실제 DOM 업데이트는 diffing 과정에서 최소화된다는 개념을 이해하고 있었다면 크게 고민하지 않아도 될 내용이였습니다.

 

이전 학습내용이 떠오르는 재미있는 토론 주제였습니다!

 

읽어주셔서 감사합니다.

 

 

 

 

호이안

해당 포스트는 하루에 하나씩 FE 개발자 면접 문제 오픈 채팅방에서 매일 출제되는 퀴즈를 토대로 학습 및 토론내용을 정리한 게시글입니다.

 

1. Quiz 및 답변

퀴즈

안녕하세요~ 좋은 하루입니다! 오늘의 FE의 질문은!!

Q1. 자바스크립트의 event loop와 call stack의 동작 방식을 설명하고, microtask와 macrotask 큐의 차이점을 설명해 주세요. 이를 통해 비동기 코드가 실행되는 순서에 대해 설명해 주세요.

답변

 싱글스레드인 자바스크립트의 실행 방식을 보완하기 위하여 브라우전 엔진 및 노드등은 이벤트 루프와 같은 설계 방식을 선택하였습니다!
이벤트 루프는 자바스크립트의 콜스택이 비게되면 태스크큐에 있는 작업을 순차적으로 실행시켜 자바스크립트에서 비동기 로직을 가능하게 합니다. 이때 큐 하나로는 비동기 작업의 우선순위 및 효율성을 지키기 어려워 **매크로 태스크 큐** 와 **마이크로 태스크 큐** 두 가지 큐를 통하여 비동기 처리의 일관성을 유지합니다.
마이크로 태스크큐는 주로 프로미스나 뮤테이션 옵져버가 들어가며, 매크로 태스크 큐는 그 이외의 대부분 비동기 작업이 들어갑니다.

2. 토론

 대부분의 답변들이 콜스택과 태스크 큐를 강조하며, 태스크 큐와 마이크로 태스크 큐의 차이점, 그리고 각 큐에는 어떤 작업들이 들어가게 되는지를 설명해 주었습니다. 이 중 이슈가 되는 답변과 그에 대한 저의 생각들을 나열해보겠습니다.

 

Q.1 '🤔 자바스크립트가 동기적으로 처리한다는 말이 약간 애매하지않을까요 ?'

 

 저는 질문의 의도를 아래와 같이 생각하였습니다.

 

[사고의 맥락]
'자바스크립트는 비동기도 되니깐 동기라고 하기에는 조금 애매한거 같다' 라고 생각을 하시고 있으신가?. 라고 생각하였으며, 그에 대해 저는 '자바스크립트 자체는 싱글 스레드로 동기가 맞으며, 비동기를 가능하게 한 것 은 런타임 에서 이벤트루프와 같은 설계를 도입하여 싱글스레드를 보완 한 것이다' 와 같이 생각하였습니다.

 

 

[당시 답변]

이와 관련하여 '동기적인데 이벤트루프, 큐로 인해서 비동기처럼 보이는거 뿐일거로 알고 있어요' 와 같은 답변들도 있었으며, 해당 질문을 통하여 토론방에서 '자바스크립트는 어떻게 비동기를 실행할까' 에 대한 이상적인 토론이 오고갔습니다.


Q.2 console.log 랑 value값이 어떻게 찍힐지 예상해보세요~!

감사하게도 이와 관련된 재미있는 문제를 올려주신분이 있습니다.

 let value = 100;

const delay = () => {
  return new Promise((resolve, reject) => {
    console.log(0, value);
    setTimeout(() => {
      console.log(1, value);

      value = 200;
      console.log(2, value);
      resolve(value);
    });
  });
};

(async () => {
  const output = await delay();
  console.log("3", output);
})();

value = 300;

 

[사고의 맥락]

1️⃣ console.log(0, value); → 0 100

  • delay() 함수가 실행되면, 동기적으로 console.log(0, value);가 실행됩니다.
  • 이 시점에서 value는 100입니다.

2️⃣ value = 300;

  • 비동기 함수인 **await delay()**는 Promise가 처리될 때까지 일시 중단됩니다.
  • value는 300으로 변경됩니다.

3️⃣ setTimeout 콜백 실행 → 1 300

  • 이벤트 루프에 의해 **setTimeout()**이 실행되면, 변경된 **value = 300**이 출력됩니다.

4️⃣ value = 200; → 2 200

  • setTimeout 내부에서 **value**가 200으로 업데이트되고, **2 200**이 출력됩니다.

5️⃣ resolve(value);

  • Promise가 fulfilled 상태가 되어, await 다음 줄이 실행될 준비가 됩니다.
  • 이때 value는 200입니다.

6️⃣ console.log("3", output); → 3 200

  • **output**에는 **resolve(value)**로 전달된 200이 저장되어 출력됩니다.

[당시 답변]

0 100

1 300

2 200

3 200

 

 

[정답]

 

 

[공유]

Node.js와 V8의 이벤트 루프 차이

V8 엔진 (브라우저 환경) Node.js의 이벤트 루프
V8 엔진에서는 이벤트 루프가 매크로태스크(예: setTimeout)보다 항상 마이크로태스크(예: Promise, process.nextTick)를 우선 처리합니다. 이는 이벤트 루프의 각 반복에서 콜 스택이 비워질 때마다 마이크로태스크 큐를 우선적으로 비우는 구조입니다. Node.js는 V8 엔진 위에 구축된 환경이지만, 이벤트 루프의 동작 방식은 libuv 라이브러리에 의해 제어됩니다. Node.js 이벤트 루프는 여러 단계로 나뉘며, 각 단계가 끝날 때마다 마이크로태스크 큐를 비우지 않습니다. 대신, 특정 단계에서만 마이크로태스크(예: Promise의 후속 작업)가 처리됩니다.

3. 후기

이전에 블로그 포스팅을 했던 내용이라 꽤 관심있게 토론을 진행하였습니다. 다시금 자바스크립트 동작원리에 대해 공부할 수 있어 좋았고 다음에 더 흥미로운 주제로 찾아 뵙겠습니다!!

+ Recent posts