[TIL]20250402

김민석·2025년 4월 2일
post-thumbnail

오늘 목표

  • 수업 전 7시 기상 후 운동(O)
  • 수업 내용 모르는 거 및 공부내용 정리(O)
  • 프로젝트 진행 해보기(O)

배운내용 및 공부내용

리액트 훅 사이트

https://ko.legacy.reactjs.org/docs/hooks-intro.html

비동기

자바스크립트는 싱글 스레드 언어이다.
싱글 스레드 언어는 한번에 하나의 작업만 수행 가능하다.
차례대로 하나의 작업만 진행하는 방식을 동기라고 부릅니다.

동기 방식은 간단하고 직관적이지만 서버에 데이터를 요청하는 상황이 발새앟면 다른 상황은 그 요청을 기다릴 떄 실행되지 않기 때문에 사용자 경험에 안좋은 영향을 끼칠 수 있습니다.

비동기는 쉽게 말해 작업을 백그라운드에 요청하여 처리되게 하여 멀티로 작업을 동시에 처리하는 것으로 보면 된다.
그렇게 되면 병렬적으로 처리하여 여러 작업이 지연되지 않아 처리하는 시간이 줄게됩니다.

그럼으로 비동기로 처리하는 것이 좋겟죠 그렇기 위해 자바스크립트 에서도
비동기를 사용 해보도록 하겠습니다.


위에 사진을 글로 설명하면

Heap

객체(Object)와 같은 참조형 데이터를 저장하는 메모리 공간
동적으로 크기가 변하며 가비지 컬렉터가 불필요한 데이터를 정리

Stack

함수 실행 순서를 관리하는 공간(LIFO)
함수를 실행하면 스택에 쌓이고 실행이 끝나면 제거됨

Web APIs

브라우저가 제공하는 비동기 기능을 처리하는 공간
JavaScript의 싱글 스레드 한계를 해결하는 핵심 요소
setTimeout(), fetch(), addEventListener() 같은 비동기 함수들은 웹 API에서 실행됨

Callback Queue

비동기 작업이 끝나면 콜백 함수가 여기에 들어감
큐(FIFO)방식으로 콜백이 대기

Event Loop

Stack이 비었을 때 Callback Queue에 있는 작업을 실행하는 역할

기본 동작:콜 스택이 비어 있는지 확인 비어 있다면 콜백 큐에서 함수를 가져와 실행을 반복함.

이벤트 루프가 있기 때문에 JavaScript가 비동기 작업을 효과적으로 처리할 수 있다.

자바스크립트는 싱글 스레드 언어인데 비동기 방식으로 처리하는가?

자바스크립트를 실행하는 Stack은 싱글 스레드 이지만 서버에게 리소스를 요청하거나 파일 입출력 같은 작업 WebAPIs는 멀티스레드이기 때문에
동시에 작업 처리가 가능하기 때문이다. 즉, 브라우저라는 소프트웨어가 멀티 스레드 이기 때문에 메인 자바스크립트 스레드를 차단하지 않고 다른 스레드를 사용하여 Web API의 작업을 처리하여 동시 처리가 가능한 것이다.

하지만 우리의 자바스크립트는 완벽한 멀티 스레딩은 아니라고 한다.
WebAPIs를 통해 병렬적으로 받아온다고 하지만 요청 후 작업 과정에서 stack에서 처리되기 떄문이다. 완벽한 멀티 스레딩은 동시성 문제가 따라와 고난이도의 지식을 요구하기 때문에 자바스크립트는 이러한 방식을 선호한 것 같다..

비동기 처리 기법

Callback

함수의 매개변수에 함수 자체를 넘기는 방법이다.
비동기는 요청과 응답의 순서를 보장하지 않는다.

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

const Login = () => {
  const [user, setUser] = useState(null);
  const [wishlist, setWishlist] = useState([]);

  // 로그인 함수 (콜백을 받아서 실행)
  const login = (username, password, callback) => {
    axios
      .post("/api/login", { username, password })
      .then((response) => {
        setUser(response.data.user);
        callback(response.data.user); // 로그인 성공 후 콜백 실행
      })
      .catch((error) => {
        console.error("로그인 실패:", error);
      });
  };

  // 위시리스트 가져오는 함수
  const fetchWishlist = (user) => {
    if (!user) return;

    axios
      .get(`/api/wishlist?userId=${user.id}`)
      .then((response) => {
        setWishlist(response.data);
      })
      .catch((error) => {
        console.error("위시리스트 불러오기 실패:", error);
      });
  };

  // 로그인 버튼 클릭 시 실행
  const handleLogin = () => {
    login("testUser", "password123", fetchWishlist);
  };

  return (
    <div>
      <button onClick={handleLogin}>로그인</button>
      <h3>위시리스트</h3>
      <ul>
        {wishlist.map((item) => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default Login;

코드 설명

1.login 함수에서 로그인 성공 시 callback(response.data.user)을 실행.
2.fetchWishlist 함수가 콜백으로 전달되어 로그인 후 자동 실행됨.
3.fetchWishlist는 받은 user 정보를 이용해 위시리스트를 가져옴.

async / awiat

async/await는 프로미스를 기반으로 하지만 동기 코드처럼 작성할 수 있게 해준다. 비동기 작업을 쉽게 읽고 이해할 수 있게 해주기 때문에 비동기 작업을 처리할 일이 있다면 async/await 방식을 쓰기도 한다.

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

const Login = () => {
  const [user, setUser] = useState(null);
  const [wishlist, setWishlist] = useState([]);

  // 로그인 함수 (async/await)
  const login = async (username, password) => {
    try {
      const response = await axios.post("/api/login", { username, password });
      setUser(response.data.user);
      return response.data.user; // user 반환
    } catch (error) {
      console.error("로그인 실패:", error);
      throw error;
    }
  };

  // 위시리스트 가져오는 함수 (async/await)
  const fetchWishlist = async (user) => {
    try {
      const response = await axios.get(`/api/wishlist?userId=${user.id}`);
      setWishlist(response.data);
    } catch (error) {
      console.error("위시리스트 불러오기 실패:", error);
    }
  };

  // 로그인 버튼 클릭 시 실행
  const handleLogin = async () => {
    try {
      const user = await login("testUser", "password123");
      await fetchWishlist(user); // 로그인 후 위시리스트 가져오기
    } catch (error) {
      console.error("에러 발생:", error);
    }
  };

  return (
    <div>
      <button onClick={handleLogin}>로그인</button>
      <h3>위시리스트</h3>
      <ul>
        {wishlist.map((item) => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default Login;

try-catch문 사용

비동기 코드에서 에러를 안전하게 처리하기 위해 try-catch를 자주 사용한다.

  • 비동기 코드에서도 예외 처리를 해서 프로그램이 멈추지 않도록 하기 위해 사용한다.
  • 콜백 함수 안에서 발생하는 에러는 try...catch로 못 잡으므로 내부에서 사용해야 함
    +비동기 작업이 실패했을 때 안전하게 처리하려면 try-catch를 꼭 쓰도록 하자!!

최적화 및 성능향상

자바스크립트에서 비동기 함수를 최적화하고 성능을 향상시키기 위한 여러 가지 방법이 있다. 이러한 방법을 통해 비동기 작업의 효율성을 높이고, 애플리케이션의 전반적인 성능을 개선할 수 있습니다. 비동기 작업을 병렬로 실행하면 성능을 크게 향상할 수 있습니다.

1. Debounce & Throttle (이벤트 최적화)

Debounce(지연 실행)

function debounce(fn, delay) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

const onSearch = debounce((query) => {
  console.log("검색 실행:", query);
}, 300);

document.getElementById("search").addEventListener("input", (e) => onSearch(e.target.value));

입력이 멈추고 일정 시간이 지나야 실행

Throttle (일정 간격으로 실행)

function throttle(fn, limit) {
  let lastCall = 0;
  return (...args) => {
    const now = Date.now();
    if (now - lastCall >= limit) {
      lastCall = now;
      fn(...args);
    }
  };
}

const onScroll = throttle(() => {
  console.log("스크롤 이벤트 실행");
}, 500);

window.addEventListener("scroll", onScroll);

지정된 시간마다 한번만 실행되게 함.

2.Lazy Loading(지연 로딩)

필요할 때만 리소스 로드하여 성능 최적화.

document.addEventListener("DOMContentLoaded", function () {
  const img = document.querySelector("img");
  img.setAttribute("loading", "lazy");
});

초기 로딩 속도 개선

지연 로딩의 또 다른 예로는 Intersection Observer를 활용하여 이미지가 화면에 들어오면 이미지를 띄우면서 성능을 최적화 시킬 수 있음.

3.Web Worker(멀티 스레드 사용)

// worker.js
onmessage = function (event) {
  let result = event.data * 2;
  postMessage(result);
};

// main.js
const worker = new Worker("worker.js");

worker.postMessage(10);
worker.onmessage = function (event) {
  console.log("Worker 결과:", event.data);
};

자주 쓰진 않지만 많은 작업(다량의 로그를 받아서 처리하는 로그시스템 등)에서 종종 사용하긴 합니다. 라고 보조 강사님이 말씀해 주셧다
다음에 기회가 되면 더 공부하고 사용해보자!!!

profile
나만의 기록장

0개의 댓글