동기식 처리 모델 vs 비동기식 처리 모델
- 동기식 처리 모델: 직렬적으로 task를 수행한다. 즉, 태스크는 순차적으로 실행되며 어떤 작업이 수행 중이면 다음 작업은 대기하게 된다. 예를 들어, 서버에서 데이터를 가져와서 화면에 렌더하는 작업을 할 때, 서버에 데이터를 요청하고 응답될 때까지 이후 태스크들은 블로킹 된다.
- 비동기식 처리 모델: 태스크가 종료되지 않은 상태라 하더라도 대기하지 않고 다음 태스크를 실행한다. 서버에 데이터를 요청한 이후 서버로부터 데이터가 응답될 때까지 기다리지 않고(Non-bloking) 즉시 다음 태스크를 수행한다. 서버에서 응답이 오면 이벤트가 발생하고, 이벤트 핸들러가 데이터를 가지고 수행할 태스크를 계속 수행한다.
function func1() {
console.log('func1');
func2();
}
function func2() {
setTimeout(function() {
console.log('func2');
}, 0);
func3();
}
function func3() {
console.log('func3');
}
func1();
해당 코드를 실행하면 setTimeout
메소드에 두번재 인수를 0초로 설정해도 func1 > func3 > func2 순서로 로그가 찍힌다. 그 이유는 setTimeout
가 비동기 함수이기 때문이다.
과정을 살펴보자.
우선 func1
이 호출되고 Call stack에 쌓인다. func1
에서 func2
를 호출하므로 Call stack에 func2
가 쌓이고 setTimeout
가 호출된다. setTimeout
의 콜백함수는 즉시 실행되지 않는다. Event Queue
에서 지정된 대기시간만큼 기다린 후 이벤트가 발생하면 task Queue
로 이동한 후에 Call Stack이 모두 비어졌을 때 Call Stack으로 이동되어 실행된다.
브라우저의 비동기 처리 방법
브라우저에서는 크게 2가지 비동기 처리 방식을 제공하고 있다.
1. XMLHttpRequest (XHR)
XMLHttpRequest
는 웹 브라우저에서 서버와 상호작용할 수 있도록 해주는 JavaScript 객체이다. 비동기적으로 데이터 요청, 응답이 이루어져 페이지가 리로드 되지 않아도 서버와 통신할 수 있다. GET, POST 같은 HTTP 메서드를 사용해서 데이터를 주고받을 수 있다.
오래전부터 다양한 브라우저에서 지원된다는 장점이 있지만, 코드가 복잡하고 FetchAPI에 비해 불편하다는 단점이 있다.
const xhr = new XMLHttpRequest(); //XMLHttpRequest 객체 생성
xhr.open("POST", "/posts"); //HTTP Method, URL 정의
xhr.setRequestHeader("content-type", "application/json"); //헤더 content-type 정의
xhr.send(JSON.stringify(data)); //JSON.stringify를 통해 오브젝트 데이터를 문자열 형태로 변경
2. Fetch API
Fetch API
는 최신 웹 표준으로, 비동기 네트워크 요청을 간단하게 처리할 수 있는 JS API이다. Promise 기반으로 동작해서 코드가 간결하고 가독성이 좋다.
Fetch API는 언제 사용하면 좋을까?
- 최신 브라우저에서 동작하는 애플리케이션
- 간결하고 가독성 좋은 코드를 작성하고 싶을 때
- 스트림 데이터 처리가 필요한 경우
반면 XMLHttpRequest
는 오래된 브라우저를 지원해야 하는 상황이나 다양한 요청, 응답 형태를 제어해야할 때 사용하면 좋다.
AXIOS
브라우저와 Node 환경에서 비동기 통신은 다르다. Node.js에서는 XMLHttpRequest
와 Fetch API
를 직접 사용할 수 없다. 따라서 Axios라는 비동기 처리 라이브러리를 사용한다.
리액트 생명주기와 마운트와 언마운트, 그리고 렌더
리액트(React)에서 컴포넌트의 렌더링 과정은 마운트(mount), 업데이트(update), 언마운트(unmount) 세 단계로 나눌 수 있다. 각각의 과정은 컴포넌트의 **생명 주기(lifecycle)**에서 중요한 역할을 한다.
- 컴포넌트의 마운트 과정: 컴포넌트가 처음 DOM에 삽입될 때 발생한다.
- constructor: 컴포넌트가 생성될 때 호출된다. 초기 state 설정 및 클래스 메서드 바인딩 등에 사용된다.
- static getDerivedStateFromProps: 컴포넌트가 마운트되기 전과 업데이트되기 전에 호출다. props로부터 state를 갱신할 때 사용된다.
- render: 컴포넌트의 UI를 정의하는 메서드로, JSX를 반환한다.
- componentDidMount: 컴포넌트가 처음으로 렌더링된 후 호출된다. 이 시점에서 DOM에 접근할 수 있으며, 비동기 작업(예: 데이터 가져오기)을 시작할 수 있다.
- 컴포넌트 업데이트 과정: props 나 state 가 변경될 때 발생한다. 컴포넌트는 이미 DOM에 존재하고 있으며, componentDidUpdate와 같은 생명 주기 메서드가 호출된다.
- 컴포넌트 언마운트 과정: 생성된 DOM 객체가 삭제되는 것
render과 mount의 차이점
- mount: 컴포넌트가 처음으로 DOM에 삽입되는 과정. 컴포넌트가 처음으로 DOM에 추가될 때 한 번만 발생한다.
- render: 리액트 컴포넌트의 메서드로, 컴포넌트가 화면에 어떻게 표시될지를 정의하는 것
props
나 state
가 변경될 때 마운트 과정을 거칠까?
props
나 state
같은 경우에는 mount를 거치지 않는다. 기존 상태를 유지하며 효율적으로 업데이트하기 위함이다.
useEffect
useEffect는 동기적으로 작동하는 함수이다. useEffect의 클린업 함수는 컴포넌트가 언마운트 될 때 실행되며, 메모리 누수를 방지하기 위해 사용된다. 덧붙여, useEffect는 컴포넌트가 렌더링 될 때마다 실행되는 것이 아니라, 의존성 배열에 명시된 값이 변경될 때만 실행되며 이는 성능 최적화에 큰 도움이 된다.
useEffect 주의점
- 무한 루프에 빠지지 않도록 주의하자. useEffect 내부에서 상태 변경할 때는 해당하는 상태가 의존성 배열에 있는지 확인하자. → 올바른 의존성 배열 관리가 필요하다.
- 클린업 함수도 중요하다. useEffect 내에서 시작된 모든 작업은 컴포넌트가 언마운트 될 때 정리되어야 한다.
useEffect 내부에서 async 함수를 직접 사용할 수 없다
useEffect가 반환하는 함수는 클린업 함수여야 하기 때문이다. async 함수는 항상 Promise
를 반환하므로, useEffect
의 클린업 함수와 충돌하는 문제가 발생할 수 있다. 이러한 문제를 피하기 위해 useEffect 내부에서 따로 비동기 함수를 정의하고 호출하는 방식으로 작업을 수행한다.
참고
'FE > 코딩일기' 카테고리의 다른 글
🌳7월12일 TIL🎶 (0) | 2024.07.12 |
---|---|
🌳7월10일 TIL🎶 (0) | 2024.07.10 |
🌳7월8일 TIL🎶 (0) | 2024.07.09 |
🌳7월5일 TIL🎶 (1) | 2024.07.05 |
🌳7월4일 TIL🎶 (0) | 2024.07.05 |