sections 2 회고 중 모의 면접 질문 모음
느낀 점 먼저 적어 보자면,
예시 코드 없이도 설명할 수 있도록 어휘적인 정리에 힘을 더 써야겠다.
프로미스는 자바스크립트에서 비동기 작업을 처리하기 위해 사용하는, 비동기 작업의 결과를 나타내는 객체입니다.
Promise를 사용하면 비동기 작업을 체인 형태로 연결하여 보다 간결한 코드를 작성할 수 있는데요. 예를 들어,
데이터를 가져오는 비동기 작업을 수행하는 fetchData 함수의 작동 이후, 이행 상태가 되면 .then 핸들러를 연결해 데이터를 가공하고 결과를 출력하는 비동기 작업을 연속적으로 처리할 수 있습니다. 거부 상태로 변경되면 catch 핸들러를 사용해 발생한 에러를 처리합니다.
정리하면, Promise를 사용함으로써 비동기 작업을 더 효율적이고 관리하기 쉬운 방식으로 처리할 수 있습니다. 이를 통해 코드의 가독성을 향상시키고, 에러 처리를 보다 간편하게 할 수 있습니다.
예상 꼬리 질문
프로미스의 세 가지 상태
대기(pending), 이행(fulfilled), 거부(rejected). 대기 상태는 비동기 작업이 아직 완료되지 않았음을 의미하며, 이행 상태는 비동기 작업이 성공적으로 완료되었음을 나타냅니다. 거부 상태는 비동기 작업이 실패하거나 에러가 발생했음을 나타냅니다.
Promise가 콜백 함수와 어떻게 다른가요?
구조와 가독성, 에러 처리 부분에서 차이가 있습니다. 프로미스와 달리 콜백 함수를 중첩하여 연쇄된 비동기 작업을 처리하면 코드가 복잡해지고 가독성이 저하되고, 에러 처리에서도 프로미스는 .catch 핸들러를 사용해 비교적 간단한 반면 콜백 함수는 체인 전체를 중단시킬 수도 있습니다.
Promise 체인 중간에 에러 발생시 어떻게 처리하나요?
Promise 체인에서 중간에 에러가 발생하면 해당 에러는 가장 가까운 .catch() 핸들러로 전달됩니다. 이를 통해 에러를 적절히 처리하고, 나머지 체인은 계속 실행될 수 있습니다.
Promise의 상태 중 '거부(rejected)' 상태가 발생하는 경우에는 어떻게 처리되나요?
Promise 객체가 거부 상태가 되면 가장 가까운 .catch() 핸들러로 에러가 전달됩니다. 이를 통해 에러를 적절히 처리할 수 있습니다. 만약 .catch() 핸들러가 없는 경우에는 에러가 무시되고 프로미스 체인은 다음 이행 상태로 이동합니다.
Promise 체인에서 여러 개의 .then() 메서드를 연속적으로 사용할 수 있나요?
네, Promise 체인에서 .then() 메서드를 여러 번 연속적으로 사용할 수 있습니다. 각 .then() 메서드는 이전 단계에서 반환된 Promise의 결과를 처리하고 새로운 Promise를 반환합니다. 이를 통해 비동기 작업을 연속적으로 체인으로 연결할 수 있습니다.
Promise가 비동기 작업을 처리할 때 어떤 이점이 있나요?
Promise를 사용하면 비동기 작업을 보다 간결하고 관리하기 쉬운 방식으로 처리할 수 있습니다. 프로미스는 체인 형태로 연결되어 코드의 가독성을 향상시키고, 비동기 작업의 순서와 종속성을 명확하게 표현할 수 있습니다. 또한, 프로미스는 에러 처리를 간편하게 할 수 있으며, 비동기 작업의 성공 또는 실패를 명확하게 나타낼 수 있습니다.
순수 함수는 동일한 입력에 대해 항상 동일한 출력을 반환하며, 외부의 상태를 변경하지 않는 함수이므로 불변성을 가지며, 사이드 이펙트를 일으키지 않도록 설계됩니다.
불변성은 객체나 데이터의 상태가 변경되지 않음을 의미하고, 사이드 이펙트는 함수가 외부의 상태를 변경하거나 다른 부작용을 일으키는 것입니다. 순수함수는 데이터의 함수 호출 시 일관성 유지되고, 함수 호출의 결과가 예측 가능하고 안정적이며, 코드를 디버깅하고 테스트하기 쉽게 만듭니다. 예를 들어,
a와 b를 더하는 sum 함수를 만들면 해당 함수는 동일한 입력에 대해 항상 동일한 출력을 반환합니다. 또한, 외부 상태를 변경하지 않고 순수하게 덧셈 연산을 수행한다는 점에서 순수 함수입니다.
정리하면, 순수 함수는 동일한 입력에 대해 항상 동일한 출력을 반환하고 외부의 상태를 변경하지 않으며, 불변성을 가지며 사이드 이펙트를 일으키지 않는 함수입니다.
예상 꼬리 질문
순수 함수의 장점은 무엇인가요?
예측 가능성(Predictability), 테스트 용이성(Testability), 모듈화(Modularity), 병렬성(Parallelism)이 있습니다.
순수 함수는 항상 사용해야 하나요? 왜 그런가요?
항상 사용해야 할 필요는 없습니다. 프로그램은 외부 상태를 변경하고 다양한 작업을 수행해야 하는 경우가 있습니다. 순수 함수를 사용하는 것은 좋은 프로그래밍 원칙이지만, 모든 경우에 절대적으로 필요하지 않다고 생각합니다. 어떤 함수는 사이드 이펙트를 필요로 하거나 외부 상태에 의존하여 작업을 수행해야 할 수 있습니다. 그러나 순수 함수를 최대한 사용하는 것은 코드의 예측 가능성과 유지보수성을 향상시키는 데 도움이 됩니다.
순수 함수와 불변성이 함수형 프로그래밍과 어떤 관련이 있나요?
순수 함수와 불변성은 함수형 프로그래밍의 핵심이라고 생각합니다. 함수형 프로그래밍은 상태 변경보다는 함수를 조합하여 프로그램을 작성하는 패러다임이고, 순수 함수와 불변성은 외부 상태의 변경을 제한하고 함수 간의 결합도를 낮춥니다. 함수형 프로그래밍에서는 이 특성을 활용해 상태 관리와 부작용을 제어하며 코드의 안정성과 유연성을 촉진합니다.
순수 함수와 불변성이 프로그램의 성능에 어떤 영향을 미칠까요?
순수 함수와 불변성은 프로그램의 성능에 긍정적인 영향을 미칠 수 있습니다. 순수 함수는 동일한 입력에 대해 항상 동일한 출력을 반환하므로, 같은 입력에 대한 결과를 캐싱하거나 재계산하지 않고 이전에 계산된 값을 재사용할 수 있습니다. 이로 인해 계산 비용이 줄어들어 성능이 향상될 수 있습니다. 또한, 불변성은 여러 개의 스레드나 프로세스에서 동시에 데이터에 접근하는 경우 경합 조건이나 동기화 문제를 방지할 수 있어 병렬 처리에 유리한 환경을 제공합니다.
순수 함수와 불변성은 코드의 유지보수성에 어떤 영향을 미칠까요?
순수 함수와 불변성은 코드의 유지보수성을 향상시킵니다. 순수 함수는 외부 상태에 의존하지 않고 독립적으로 동작하므로, 코드의 일관성과 예측 가능성이 높아집니다. 이는 버그를 예방하고 디버깅을 용이하게 만듭니다. 또한, 불변성은 객체나 데이터의 상태가 변경되지 않으므로 코드를 이해하기 쉽고 예측 가능한 방식으로 작성할 수 있습니다. 변경이 필요한 경우에도 새로운 객체를 생성하여 기존 객체를 변경하지 않는 방식으로 코드를 작성하면, 코드의 부작용을 최소화하고 유지보수성을 높일 수 있습니다.
순수 함수와 불변성은 어떤 상황에서 유용하게 적용될 수 있나요?
순수 함수와 불변성은 다양한 상황에서 유용하게 적용될 수 있습니다. 특히 병렬 처리, 캐싱, 테스트 등의 분야에서 많은 장점을 제공합니다. 순수 함수는 동일한 입력에 대해 항상 동일한 출력을 반환하므로, 병렬 처리 환경에서 여러 스레드나 프로세스에서 안전하게 사용될 수 있습니다. 불변성은 데이터의 변경을 제한하여 예측 가능한 코드를 작성하고, 캐싱을 통해 성능을 개선하거나 테스트 작성을 용이하게 합니다. 또한, 함수형 프로그래밍 패러다임에서 순수 함수와 불변성을 활용하여 코드의 모듈화와 결합도를 낮추는 데에도 유용하게 적용될 수 있습니다.
state는 컴포넌트 내부에서 관리되는 데이터로, 값이 변경될 수 있고 컴포넌트를 다시 렌더링하여 변경 사항을 반영합니다. props는 부모 컴포넌트로부터 전달되는 읽기 전용 데이터로, 컴포넌트 간의 데이터 전달과 상태 공유에 사용됩니다.
state는 주로 컴포넌트의 내부 상태를 저장하고 업데이트하는 데 사용됩니다. setState() 메서드를 통해 변경됩니다. 반면 주로 컴포넌트 간의 데이터 전달 및 상태 공유에 사용되는 props는 컴포넌트 내부에서 변경할 수 없는 읽기 전용입니다. 부모 컴포넌트에서 props를 변경하면 해당 값을 전달받은 자식 컴포넌트도 다시 렌더링되어 변경 사항을 반영합니다. 예를 들어,
현재 값을 나타내는 count state를 가지고 있고, setCount 함수를 사용하여 count state를 업데이트하는 Counter 컴포넌트를 만듭니다. 이 컴포넌트는 버튼 클릭 시 increment 함수를 호출하여 count 값을 증가시키고, 메시지를 나타내기 위해 message props를 받아와 출력할 수 있습니다.
예상 꼬리 질문
state와 props의 차이점은 무엇인가요?
state는 컴포넌트 내부에서 변경하고 관리할 수 있지만, props는 외부에서 설정되며 컴포넌트 내에서 변경할 수 없습니다.
state 값을 변경할 때 왜 setState()를 사용해야 하나요?
React가 state 변경을 감지하고 컴포넌트를 다시 렌더링하여 변경 사항을 UI에 반영하기 위해서입니다. setState()를 호출하면 React는 변경된 state를 비동기적으로 처리하고, 필요한 경우에만 컴포넌트를 업데이트합니다. 이는 효율적인 렌더링을 가능하게 합니다.
state와 props는 어떤 상황에서 사용하면 좋을까요?
state와 props는 각각 다른 용도와 제한 사항을 가지고 있으므로, 상황에 맞게 적절히 사용해야 합니다. state는 컴포넌트가 자체적으로 유지해야 하는 데이터나 사용자와의 상호작용에 따라 변경되는 값들을 관리할 때 사용합니다. props는 컴포넌트 간의 데이터 전달과 상태 공유에 사용됩니다.
state를 변경할 때 setState() 대신에 직접 state 값을 수정하면 안 될까요?
React에서는 setState() 메서드를 사용하여 state 값을 변경해야 합니다. 직접 state 값을 수정하면 React가 변경 사항을 감지하지 못하고, 컴포넌트를 제대로 업데이트하지 못할 수 있습니다. setState() 메서드를 사용하면 React는 변경된 state를 비동기적으로 처리하고, 필요한 경우에만 컴포넌트를 업데이트하여 효율적인 렌더링을 할 수 있습니다.
props는 읽기 전용이라고 했는데, 컴포넌트 내에서 props 값을 변경하려면 어떻게 해야 하나요?
props는 부모 컴포넌트로부터 전달되는 읽기 전용 데이터이기 때문에 컴포넌트 내에서 직접 변경할 수 없습니다. 만약 props 값을 변경해야 한다면, 부모 컴포넌트에서 새로운 props 값을 전달하여 업데이트해야 합니다. 이 때 부모 컴포넌트에서의 props 변경이 발생하면 해당 값을 전달받은 자식 컴포넌트도 다시 렌더링되어 변경 사항을 반영할 수 있습니다.
state와 props는 함수형 컴포넌트에서도 사용할 수 있나요?
예, React의 최신 버전에서는 함수형 컴포넌트에서도 state와 props를 사용할 수 있습니다. React Hooks를 사용하면 함수형 컴포넌트에서도 상태를 관리할 수 있도록 useState 훅을 사용할 수 있고, props는 함수의 매개변수로 전달받아 사용할 수 있습니다. 함수형 컴포넌트는 기능적으로 간단하고 가벼워서 코드의 가독성과 재사용성을 높일 수 있으며, state와 props를 활용하여 컴포넌트를 작성할 수 있습니다.
React 컴포넌트의 key 속성은 컴포넌트 리스트에서 각 항목을 구분하는 역할을 합니다. key는 React가 컴포넌트를 업데이트할 때 각 요소를 고유하게 식별하는 데 사용됩니다.
key 속성이 사용되는 목적은 다양합니다.
예를 들어,
할일 목록을 만들 때, todolist라는 함수 선언 후 todos라는 인자를 받아옵니다. todos에 map 메서드를 사용하여 map 내부 함수의 매개변수로 todo를 받을 때, todo 항목은 고유한 id 값을 가지고 있으며, 이를 key 속성으로 사용하게 됩니다. 이렇게 key를 지정하면 React는 각 todo 항목을 식별하여 효율적으로 업데이트하고 재배열합니다.
정리하면, key 속성은 컴포넌트 리스트에서 각 항목을 고유하게 식별 합니다. React는 key를 사용하여 업데이트 성능을 최적화하고 요소의 재배열을 식별합니다.
예상 꼬리 질문
key 속성을 지정하지 않으면 어떤 문제가 발생할 수 있나요?
key를 지정하지 않은 경우 컴포넌트 리스트의 항목이 추가, 제거, 재배열되는 경우에 예기치 않은 동작이 발생할 수 있습니다.
key 속성은 항상 고유한 값이어야 하나요?
동일한 컴포넌트 리스트 내에서 중복된 key 값을 사용하면 React는 경고를 표시하고 예상치 못한 동작을 일으킬 수 있으므로, 고유한 key 값을 사용해야 합니다.
key 값을 중복하여 사용하면 어떤 문제가 발생할까요?
동일한 컴포넌트 리스트 내에서 중복된 key 값을 사용하면 React는 경고를 표시하고 예상치 못한 동작을 일으킬 수 있습니다. React는 key를 사용하여 각 요소를 고유하게 식별하고, key 값이 중복되면 요소를 올바르게 업데이트할 수 없게 됩니다. 예를 들어, 중복된 key 값이 있는 경우에는 컴포넌트의 순서가 변경되어도 해당 요소를 재배열하지 않고, 이전 상태를 유지하는 등의 예기치 못한 동작이 발생할 수 있습니다.
key 값으로 어떤 값들을 사용하는 것이 좋을까요?
key 값으로는 주로 고유한 식별자인 id 값이나 데이터의 고유한 속성 값을 사용하는 것이 좋습니다. 일반적으로 데이터베이스의 id, UUID(Universally Unique Identifier), 인덱스 번호 등이 사용될 수 있습니다. 고유한 값이면서 예측 가능한 값인 경우에는 성능을 높이는 데 도움이 될 수 있습니다. 그러나 key 값으로 인덱스 번호를 사용하는 것은 추천되지 않습니다. 인덱스 번호는 요소의 순서가 변경될 때 예상치 못한 결과를 가져올 수 있기 때문입니다.
useEffect 훅은 React 컴포넌트에서 부작용(사이드 이펙트)를 수행하기 위해 사용됩니다. dependency array, 의존성 배열은 useEffect에 전달되는 두 번째 매개변수로, 어떤 값들에 의존하는지를 지정하는 역할을 합니다.
useEffect는 기본적으로 컴포넌트가 렌더링될 때마다 실행되지만, dependency array를 사용하여 특정 값들이 변경될 때에만 실행되도록 제어할 수 있어 불필요한 부작용의 실행을 방지하고, 성능을 최적화할 수 있습니다.
예를 들어,
화면에 현재 count 값을 표시하고 버튼을 클릭할 때마다 count 값을 증가시키면서, count 값의 변경 여부를 콘솔에 출력하는 기능을 가진 Example 컴포넌트를 만듭니다. useEffect 훅을 사용하여 부작용을 처리할 때, count 값이 변경될 때마다 콜백 함수가 실행되도록 설정하면 연결해 놓은 버튼을 클릭할 때마다 setCount 함수를 호출하여 count 값을 1씩 증가시킬 수 있습니다.
예상 꼬리 질문
dependency array를 사용하지 않는 경우에는 어떤 동작이 발생하나요?
어떤 값의 변경 여부와 관계없이 매 렌더링마다 콜백 함수가 실행됩니다. useEffect가 의존성 배열이 없는 상태로 동작하기 때문입니다.
dependency array에 여러 개의 값들을 포함할 수 있나요?
네. 배열 내에 포함된 값들은 useEffect가 해당 값들 중 하나라도 변경되었을 때에만 콜백 함수를 실행하도록 의존성을 설정하는 역할을 합니다. 따라서, 배열 내의 값들 중 하나라도 변경되지 않았다면 콜백 함수는 실행되지 않습니다. 예를 들어, [count, name]와 같이 여러 개의 값들을 포함한 dependency array를 사용할 수 있습니다.
CSR(클라이언트 사이드 렌더링)과 SSR(서버 사이드 렌더링)은 웹 애플리케이션에서 페이지의 렌더링 방식을 나타냅니다. CSR은 사용자 경험을 향상시키고 앱의 인터랙티브한 기능을 구현하는 데 유용하지만, 초기 로딩 시간이 길어질 수 있습니다. SSR은 사용자에게 초기 렌더링 시 데이터가 포함된 페이지를 제공할 수 있습니다. 그러나 서버 측에서 렌더링을 처리해야 하므로 서버 리소스가 필요합니다.
CSR은 초기 페이지 요청 시 서버에서는 빈 HTML 페이지를 반환하고, 이후 클라이언트 측 JavaScript가 실행되어 페이지를 동적으로 렌더링합니다. 클라이언트 측 JavaScript가 실행되기 전까지는 페이지에 실제 내용이 표시되지 않으며, 이후 데이터를 서버로부터 가져와 화면에 렌더링하는 방식입니다.
반면 SSR은 초기 페이지 요청 시 서버에서 페이지의 내용을 렌더링한 후, 완전한 HTML 페이지를 클라이언트에게 반환합니다. 서버 측에서 렌더링이 이루어지므로 초기 로딩 시간이 짧고, 검색 엔진 최적화(SEO)에 유리합니다.
예를 들어, CSR의 경우 클라이언트는 초기에 빈 페이지를 받고, JavaScript가 실행되어 데이터를 로드하고 렌더링하는 동안 사용자는 화면에 아무 내용도 보지 못합니다. 그리고 데이터를 받아서 화면이 업데이트되어 최종적으로 내용이 표시됩니다. 반면에 SSR의 경우 서버에서 초기 페이지를 완전한 형태로 렌더링하여 사용자에게 전달하므로, 초기 로딩 시간이 짧고 사용자는 페이지의 내용을 즉시 볼 수 있습니다.
콜백 함수는 다른 함수에게 인자로 전달되어 나중에 호출되는 함수입니다. 비동기적인 작업이나 이벤트 핸들링 등에서 주로 사용됩니다. 개념적인 부분은 JavaScript의 함수가 일급 객체로 다루어지는 특성을 기반으로 하는데요, 함수는 변수에 할당되거나 인자로 전달될 수 있으며, 이를 활용하여 콜백 함수를 사용할 수 있습니다.
setTimeout 함수를 사용한 콜백 함수의 예시를 하나 들겠습니다.
setTimeout(() => {
console.log('Callback function executed.');
}, 1000);
setTimeout 함수는 일정 시간이 지난 후에 콜백 함수를 실행하는 함수입니다. setTimeout 함수의 첫 번째 인자로 콜백 함수를 전달하고, 두 번째 인자로 지연 시간을 전달합니다. 지정된 시간이 경과하면 JavaScript 엔진은 해당 콜백 함수를 실행합니다. 예시 코드에서는 1초(1000밀리초) 후에 콜백 함수가 실행되며, "Callback function executed."라는 메시지가 출력됩니다.
첫 번째, 코드를 리팩토링합니다. 콜백 함수를 외부로 분리하거나, 콜백 함수를 세분화하여 모듈화하는 방법을 사용할 수 있습니다.
두 번째, 프로미스를 사용합니다. 콜백 함수 대신 프로미스를 반환하는 비동기 함수를 사용, 프로미스 체이닝을 통해 비동기 작업의 순서와 에러 처리를 명확하게 관리할 수 있습니다.
두 번째 방법에 대한 예시 코드를 작성해 보겠습니다.
// 콜백 함수
asyncFunc1(arg1, (result1) => {
asyncFunc2(result1, (result2) => {
asyncFunc3(result2, (result3) => {
// 생략
});
});
});
// 프로미스
asyncFunc1(arg1)
.then((result1) => asyncFunc2(result1))
.then((result2) => asyncFunc3(result2))
.then((result3) => {
// ...
})
.catch((error) => {
// 에러 처리
});
예상 꼬리 질문
콜백 지옥을 해결하기 위해 프로미스를 사용하는 것 외에 다른 방법은 없을까요?
콜백 지옥을 해결하기 위해 프로미스를 사용하는 것 외에도, 최신 JavaScript에서는 async/await 문법을 사용할 수 있습니다. async/await는 프로미스를 기반으로 하며, 코드를 보다 동기적으로 작성할 수 있는 문법적인 편의를 제공합니다. async 함수 내에서 await 키워드를 사용하여 비동기 작업이 완료될 때까지 대기하고, 작업이 완료되면 결과 값을 반환합니다.
프로미스와 콜백 함수의 차이점은 무엇인가요?
프로미스와 콜백 함수는 비동기 작업을 다루는 두 가지 접근 방식입니다. 콜백 함수는 비동기 작업이 완료되면 호출되는 함수이고 함수 스코프가 존재하며, 이 함수에 결과값이나 에러가 전달됩니다. 반면 프로미스는 비동기 작업을 추상화한 객체로, 성공 시 결과 값을 반환하고 실패 시 에러를 반환하는 메커니즘입니다.
깊은 복사(Deep Copy)와 얕은 복사(Shallow Copy)는 객체나 배열을 복사할 때의 차이를 나타냅니다.
const originalObj = { a: 1, b: { c: 2 } };
// Deep copy: JSON.parse(), JSON.stringify()
const deepCopyObj = JSON.parse(JSON.stringify(originalObj));
deepCopyObj.b.c = 3;
console.log(originalObj); // { a: 1, b: { c: 2 } }
console.log(deepCopyObj); // { a: 1, b: { c: 3 } }
// Shallow copy: spread 연산자
const shallowCopyObj = { ...originalObj };
shallowCopyObj.b.c = 3;
console.log(originalObj); // { a: 1, b: { c: 3 } }
console.log(shallowCopyObj); // { a: 1, b: { c: 3 } }
깊은 복사본에서는 b.c 속성을 수정해도 원래 객체에는 영향을 주지 않고, 얕은 복사본에서는 b.c 속성을 수정하면 원래 객체도 변경됩니다.
따라서 깊은 복사는 객체나 배열의 모든 내용을 새로운 메모리 공간에 복사해 원본과 완전히 독립적인 개체로 간주되는 반면, 얕은 복사는 객체나 배열의 참조만을 복사하여 새로운 변수에 할당합니다. 복사된 변수와 원본은 같은 객체를 참조하므로 하위 객체의 변경이 원본에 영향을 줍니다.
예상 꼬리 질문
깊은 복사는 원본과 완전히 독립적인 복사본을 생성하므로, 원본 객체를 변경하지 않고 독립적으로 처리해야 할 때 유용합니다. 예를 들어, 원본 객체를 보존하면서 해당 객체를 수정하고자 할 때 깊은 복사를 사용할 수 있습니다.
얕은 복사는 원본 객체와 복사본이 참조 관계를 유지하기 때문에, 복사본을 통해 원본 객체를 변경하고자 할 때 사용할 수 있습니다. 원본 객체의 특정 속성 값을 수정하거나 참조를 공유하는 상황에서 유용합니다.
JSON.parse()와 JSON.stringify()를 사용하는 방법은 일반적으로 객체와 배열의 직렬화와 역직렬화를 통해 깊은 복사를 수행합니다. 하지만 이 방법은 일부 제약 사항이 있습니다.
JSON.stringify()를 사용하여 객체나 배열을 직렬화할 때, 함수나 undefined와 같은 값들은 직렬화되지 않습니다. 따라서 깊은 복사본에는 해당 값들이 포함되지 않을 수 있습니다.
JSON.stringify()를 통해 직렬화된 문자열은 JSON.parse()로 역직렬화할 때, 모든 객체의 속성 값이 문자열로 변환됩니다. 따라서 숫자나 불리언 값은 문자열로 변환되어 복사본에 포함됩니다.
브라우저 렌더링은 사용자가 웹 페이지를 열었을 때, HTML, CSS, JavaScript 등의 리소스를 처리하여 화면에 내용을 표시하는 과정입니다.
예시로 설명해 보면,
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Hello, World!</h1>
<p>Welcome to the example page.</p>
<img src="image.jpg" alt="Example Image">
<script src="script.js"></script>
</body>
</html>
예상 꼬리 질문
일반적으로 script 태그는 body 종료 태그 바로 앞에 위치시키는 것이 좋습니다. 이는 HTML 파싱이 끝난 후에 JavaScript 파일을 로드하고 실행하기 때문에 페이지의 초기 렌더링에 방해가 되지 않습니다. 또한, 이 방법은 페이지의 로딩 속도를 향상시킬 수 있습니다.
브라우저는 CSS 파일들을 병렬로 다운로드하며, 각각을 파싱하여 스타일 규칙을 해석합니다. 여러 개의 CSS 파일이 있는 경우에는 파일들의 다운로드 순서와 네트워크 속도에 따라 파싱이 진행됩니다. 일반적으로 먼저 다운로드된 CSS 파일부터 파싱되며, 파싱이 완료된 스타일 규칙은 즉시 적용됩니다.
DOM이나 CSS 스타일이 변경되면, 브라우저는 해당 변경 사항을 감지하고 다시 렌더링을 수행합니다. 변경된 DOM 요소나 스타일 규칙은 렌더 트리에 반영되고, 레이아웃과 페인팅 단계를 거쳐 변경된 내용이 화면에 반영됩니다. 이러한 과정을 리플로우(Reflow)와 리페인팅(Repaint)이라고도 합니다. 브라우저는 최적화를 통해 필요한 부분만 다시 렌더링하여 성능을 향상시키려고 합니다.
React는 UI를 구성하는 컴포넌트 기반의 라이브러리로, 화면에 표시되는 요소들의 상태 변화에 따라 UI를 업데이트합니다. 그리고 이러한 업데이트 과정에서 가상 DOM이 사용됩니다.
가상 DOM은 실제 DOM과 유사한 구조를 가지고 있는 JavaScript 객체입니다.
예를 들어,
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
이 코드에서는 count라는 상태가 변경될 때 해당 부분만 업데이트되어야 합니다. React에서 진행되는 과정을 설명하겠습니다.
이처럼 가상 DOM을 사용함으로써, React는 UI 업데이트를 효율적으로 처리할 수 있습니다. 변경된 부분만 감지하고 업데이트함으로써 성능을 향상시킬 수 있습니다.
예상 꼬리 질문
가상 DOM은 React가 UI 업데이트를 효율적으로 처리하기 위한 방법 중 하나입니다. 일반적으로 UI가 복잡하고 대규모인 경우에 가상 DOM을 사용하는 것이 더 효과적입니다. 하지만 UI가 단순하고 작은 규모인 경우에는 가상 DOM을 도입할 필요가 없을 수 있습니다. 성능 개선을 위해 가상 DOM을 사용할지 여부는 상황에 따라 결정되어야 합니다.
React에서는 가상 DOM을 비교하여 변경된 부분을 찾는 알고리즘으로 Virtual DOM Diffing 알고리즘을 사용합니다. 이 알고리즘은 이전 가상 DOM과 새로운 가상 DOM을 비교하면서 변경된 부분을 효율적으로 찾아내고, 필요한 부분만을 실제 DOM에 반영합니다. Diffing 알고리즘은 React의 성능과 효율성에 큰 영향을 미치는 요소 중 하나입니다.
가상 DOM을 사용하면 UI 업데이트 과정에서 변경된 부분만을 감지하고 업데이트할 수 있습니다. 이로써 실제 DOM 조작을 최소화하고, 불필요한 렌더링을 방지할 수 있습니다. 또한, 가상 DOM은 여러 플랫폼에 대한 이식성도 좋아서 React Native 등과 같은 다른 플랫폼에서도 활용될 수 있습니다.