[React] Event Loop 개념 설명과 컴포넌트 구현 예시

김현수·2023년 12월 12일
0

React

목록 보기
13/29


🖋️ Event Loop 이해하면서 컴포넌트 구현하기


JavaScript의 이벤트 루프를 이해하는 것은
특히 React의 컨텍스트에서 효율적이고
반응성이 뛰어난 애플리케이션을 작성하는 데 매우 중요


📰 알아보기

이벤트 루프가 어떻게 작동하는지 분석한 다음
React 구성 요소 이벤트 처리 시나리오와 연결


  • 호출 스택

@ LIFO(Last In, First Out) 구조
@ JavaScript 가 함수 호출(실행 컨텍스트)을 추적

* 스택에 푸시되는 마지막 함수가 실행이 완료되면 가장 먼저 팝오프
  • 콜백 대기열 (큐)

@ 비동기 이벤트가 발생하면 해당 콜백이 작업 큐(또는 콜백 큐)로 푸시
  (예: setTimeout 과 AJAX 호출 또는 사용자 이벤트)

@ 콜백은 호출 스택이 비어 있을 때까지
  (즉, 현재 실행 중인 모든 스크립트가 완료될 때까지) 큐에서 대기

@ 이벤트 루프

  • 프로세스 과정
    • 호출 스택이 비어있는지 지속적으로 확인
    • if (호출 스택 isEmpty) && !(콜백 큐 isEmpty)
      • EventLoop 는 호출 스택.Push(콜백 큐 첫 번째 콜백 방출(shift))
      • 실행

    • 이 주기는 EventLoop 가 콜백을 사용 가능하게 되면
      호출 스택으로 이동하면서 계속 실행

  • 응답성 보장
    • 이벤트 루프를 사용하면서 JavaScript 가 UI 의 응답성을 유지
    • 많은 수의 동시 작업 처리 가능

  • CODE
console.log('Start'); // 1st: call stack 에서 즉시 처리

setTimeout(() => {
    console.log('Inside setTimeout'); // 3rd: callback queue 에서 지연 후 실행
}, 0);

console.log('End'); // 2nd: 'Start' 이후 callstack 에 push 되며 실행



@ React 컴포넌트 이벤트 처리 및 이벤트 루프


React 에서 이벤트는 네이티브 브라우저 이벤트에 대한
브라우저 간 인터페이스 제공하는 SyntheticEvent 를 통해 관리

  • CODE
import React, { useState } from 'react';

function MyComponent() {
    const [clickCount, setClickCount] = useState(0);

    const handleClick = () => {
        // 비동기 작업 (setTimeout 으로 시뮬레이션)
        setTimeout(() => {
            setClickCount(clickCount + 1);
            console.log('Clicked', clickCount + 1, 'times');
        }, 1000);
    };

    return <button onClick={handleClick}>Click me</button>;
}

  • 설명

    • 사용자와 상호 작용
      • handleClick 단추를 클릭하면 호출

    • 비동기 Timeout
      • handleClick 내에는 setTimeout 이 존재, 해당 함수는 비동기
      • 해당 콜백은 지정된 시간 제한 후 콜백 큐에 추가

    • 이벤트 루프
      • 현재 호출 스택이 비어있다면 (handleClick 함수 포함)
      • EventLoop 는 setTimeout 으로 Callback 을 호출 스택으로 전송

    • 상태 업데이트
      • 상태가 비동기적으로 업데이트
      • React 는 상태 업데이트가 일괄처리 때문에 보다 효율적인 렌더링 가능



@ React 에서 이벤트 루프 활용 및 최적화

  • 주 스레드 차단 방지
    • 장기 실행 동기 작업을 최소화하여 호출 스택 명확하게 유지
    • UI 가 계속 응답 가능

  • 현명하게 비동기 작업 사용
    • 데이터 가져오기 또는 과도한 계산과 같은 작업을 위해
    • Promises 또는 Async-Await 와 같은 비동기 작업 활용

  • Throttle & Debounce
    • 자주 트리거되는 Event Handler 의 경우(scroll or resize)에
      사용하여 콜백 실행 횟수 제한

  • 업데이트 일괄 처리
    • 자연스럽게 업데이트를 일괄 처리하고 효율적 실행
    • 비동기 콜백 내에서 상태를 설정할 때 유의

@ Promises 와 Async-Await 이용한 이벤트 루프


  • Promises
    • 비동기 작업의 최종 완료 또는 실패

  • Async-Await
    • async : 함수가 Promises 반환 전 사용 가능
    • await : promises 해결될 때까지 기다리는데 사용

  • Only Promises CODE
function fetchData() {
    return new Promise(resolve => {
        setTimeout(() => resolve('Data fetched'), 1000);
    });
}

function processData() {
    console.log('Start processing (inside promise)'); // 2nd
    return fetchData()  // 3rd
        .then((data) => {
            // 5th 1초뒤 data 로그
      		console.log(data);
            // 6th 
            console.log('Data processed (inside promise)'); 
        });
}

console.log('Before calling processData'); // 1st
processData()
    .then(() => {
        // 7th
        console.log('After processData is resolved');
    });
console.log('After calling processData'); // 4th
  • 실행
Before calling processData
Start processing (inside promise)
After calling processData
Data fetched
Data processed (inside promise)
After processData is resolved

  • Async-Await CODE
function fetchData() {
    return new Promise(resolve => {
        setTimeout(() => resolve('Data fetched'), 1000);
    });
}

async function processData() {
    console.log('Start processing'); // 2nd: 즉시 실행
    const data = await fetchData(); // 3rd: Promise 해결될 때까지 대기
    console.log(data); // 5th: Promise 해결된 후 실행
    console.log('End processing'); // 6th: Follows after the above console.log
}

console.log('Before processing'); // 1st: 즉시 실행

processData();

// 4th: processData 비동기 실행 이전에 외부 동기 코드 실행
console.log('After processing'); 
  • 실행
Before processing
Start processing
After processing
Data fetched
End processing
* JavaScript에서 함수 내에서 async-await 사용할 때 

- 해당 함수의 실행은 비동기 작업의 키워드에서 일시 중지
- JavaScript 런타임은 해당 함수 외부의 다른 동기 코드를 계속 실행
- 비동기 작업이 해결되면 함수 내의 실행이 동기식인 것처럼 다시 시작
profile
일단 한다

0개의 댓글