[React] 비동기 처리 설명: 호출 스택, 이벤트 루프, 백그라운드, 태스크 큐

현재·2024년 6월 11일

React

목록 보기
6/7
post-thumbnail

"비동기 프로그래밍 입문" 강의를 듣던 중, Promise와 async/await를 통해 비동기 작업을 다루는 방법을 듣게 되었는데 다루는 방법은 알고 있었지만, 원론적인 작동 방식이 궁금하다는 생각이 들었다. 그래서 React에서 비동기 작업이 어떻게 처리되는지, 호출 스택, 이벤트 루프, 백그라운드, 태스크 큐를 중심으로 정리 해본다.

비동기 작업의 처리 메커니즘을 그림으로 표현한 것이다.
용어 마다 개념을 알아보자.

호출 스택 (Call Stack):

  • 자바스크립트 코드가 실행되는 곳이며 함수들이 실행 되는 공간이다. 함수 호출이 스택에 쌓이고, 완료되면 스택에서 제거된다.

이벤트 루프 (Event Loop):

  • 호출 스택이 비어 있는지 확인하고, 비어 있다면 태스크 큐(Task Queue)에서 대기 중인 콜백을 하나씩 꺼내 호출 스택으로 이동시켜 실행해주는 역할이다.

백그라운드 (Background):

  • 비동기 작업이 실행되는 곳으로써, 타이머, 네트워크 요청 등의 비동기 작업이 여기서 처리된다.

태스크 큐 (Task Queue):

  • 비동기 작업의 콜백 함수가 대기하는 큐이다. 타이머, 네트워크 요청 등, 작업들이 완료되면 콜백 함수가 태스크 큐에 추가된다.

코드예시를 통해 좀 더 알아보자!

React 예제

import React, { useEffect, useState } from "react";
import axios from "axios";

const App = () => {
  const [todo, setTodo] = useState({ title: "" });
  const [todos, setTodos] = useState(null);

  const [targetId, setTargetId] = useState(null);
  const [editTodo, setEditTodo] = useState({ title: "" });

  const fetchTodos = async () => {
    const { data } = await axios.get("http://localhost:4000/todos");
    setTodos(data);
  };

  const onSubmitHandler = (todo) => {
    axios.post("http://localhost:4000/todos", todo);
  };

  const onClickDeleteButtonHandler = (todoId) => {
    axios.delete(`http://localhost:4000/todos/${todoId}`);
  };

  const onClickEditButtonHandler = (todoId, edit) => {
    axios.patch(`http://localhost:4000/todos/${todoId}`, edit);
  };

  useEffect(() => {
    fetchTodos();
  }, []);

  return (
    <>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          onSubmitHandler(todo);
        }}
      >
        <div>
          <input
            type="text"
            placeholder="수정하고싶은 Todo ID"
            onChange={(ev) => {
              setTargetId(ev.target.value);
            }}
          />
          <input
            type="text"
            placeholder="수정값 입력"
            onChange={(ev) => {
              setEditTodo({
                ...editTodo,
                title: ev.target.value,
              });
            }}
          />
          <button
            type="button"
            onClick={() => onClickEditButtonHandler(targetId, editTodo)}
          >
            수정하기
          </button>
        </div>
        <input
          type="text"
          onChange={(ev) => {
            const { value } = ev.target;
            setTodo({
              ...todo,
              title: value,
            });
          }}
        />
        <button>추가하기</button>
      </form>
      <div>
        {todos?.map((todo) => (
          <div key={todo.id}>
            {todo.id} : {todo.title}
            <button
              type="button"
              onClick={() => onClickDeleteButtonHandler(todo.id)}
            >
              삭제하기
            </button>
          </div>
        ))}
      </div>
    </>
  );
};

export default App;

React에서 비동기 작업이 어떻게 처리되는지, 전체적인 코드 흐름을 통해 알아보자.

컴포넌트 마운트 시:

  • useEffect 훅이 실행되고 fetchTodos 함수를 호출하여 서버에서 todos 데이터를 가져온다.
  • fetchTodos 함수는 비동기 작업으로, axios.get을 사용하여 서버에서 데이터를 가져온다. 이 작업은 백그라운드에서 실행되며, 완료 후 태스크 큐콜백이 추가된다.
  • 이벤트 루프 호출 스택이 비어 있을 때 태스크 큐에서 콜백을 호출 스택으로 이동시켜 실행하고, setTodos 함수를 통해 상태를 업데이트한다.

폼 제출 시:

fetchTodos 함수

const fetchTodos = async () => {
  const { data } = await axios.get("http://localhost:4000/todos");
  setTodos(data);
};
  • 호출 스택: fetchTodos -> axios.get
  • 백그라운드: axios.get 비동기 작업 시작, await로 인해 fetchTodos 일시 중단
  • 태스크 큐: axios.get 완료 후 콜백 태스크 큐에 추가
  • 이벤트 루프: 호출 스택 비어있으면 태스크 큐에서 콜백 실행,

나머지 onSubmitHandle, onClickDeleteButtonHandler, onClickEditButtonHandler함수의 비동기적 처리 방법은 동일하므로 생략한다.

profile
📖📚 공부 블로그

0개의 댓글