☁️ goormTIL | Web #47

매루·2025년 11월 14일

goormTIL

목록 보기
45/67
post-thumbnail

📅 2025-11-14

➡️ Throttling · Debouncing · Auth에 대해 새롭게 알게 된 것 또는 헷갈리는 부분 정리


🔎 학습 리마인드

📌 Throttling & Debouncing

  • 브라우저에서는 스크롤, 입력, 마우스 이동 같은 이벤트가 아주 짧은 간격으로 수십~수백 번 발생할 수 있음
  • 이를 그대로 처리하면 리소스 낭비와 렌더링 지연이 생기기 때문에, 이벤트 발생 횟수를 제어하는 기법이 필요
  • 대표적인 방식이 바로 Throttling(쓰로틀링)Debouncing(디바운싱)
  • 두 방식 모두 Timer(Web API)의 setTimeout을 기반으로 구현할 수 있고, 프론트엔드 성능 최적화에서 자주 등장하는 패턴

💡 Throttling이란?

  • 짧은 시간 간격으로 연속해서 발생한 이벤트들을 일정기간 단위로 그룹화하여 처음 또는 마지막 이벤트 핸들러만 호출되도록 하는 것
  • 주로 무한 스크롤에서 사용

💡 Throttling 패턴

  1. Leading Edge
    • 이벤트가 처음 발생할 때 즉시 실행, 이후 delay 동안 추가 실행 X

  1. Trailing Edge
    • 마지막 이벤트가 발생한 뒤 delay가 지나면 실행, 주기 마지막에 한 번만 처리됨

  1. Leading & Trailing
    • 첫 이벤트에 즉시 실행 + delay 마지막에도 한 번 더 실행

💡 Debouncing이란?

  • 이벤트가 연속해서 발생하면 무시하고, 마지막 이벤트 이후 일정 시간(delay)이 지난 뒤 한 번만 실행되도록 하는 방식
  • 주로 입력값 실시간 검색, 화면 resize 이벤트 등에 사용


💡 setTimeout과 메모리 누수 (Memory Leak)

메모리 누수

  • 더 이상 필요 없는 메모리가 해제되지 않고 남아있는 상황

setTimeout 때문에 메모리 누수가 발생하는 이유

  • SPA(React)에서 페이지 이동 시 컴포넌트가 언마운트되는데, 아직 실행 중인 타이머를 clearTimeout 하지 않으면 컴포넌트는 사라져도 타이머는 남아 계속 메모리를 점유한다 → 메모리 누수 발생 → 언마운트 시 반드시 clearTimeout 필요

💡 실습

import { useEffect } from 'react';

const Home = () => {
    let timerId = null;

    const throttle = (delay) => {
        if (timerId) {
            // setTimeout이 진행중인 상태, 딜레이가 경과되지 않는 상태
            return;
        }

        console.log(`api 요청 실행 ${delay}ms 동안 추가 요청 안받아요`);

        timerId = setTimeout(() => {
            console.log(`${delay}ms 지남, 추가 요청 반응`);
            timerId = null;
        }, delay);
    };

    const debounce = (delay) => {
        if (timerId) {
            // 할당 되어 있는 timerId를 타이머에서 제거
            clearTimeout(timerId);
        }

        timerId = setTimeout(() => {
            console.log(`마지막 요청 ${delay}ms 지남, 추가 요청 반응`);
            timerId = null;
        }, delay);
    };

    useEffect(() => {
        return () => {
            // 언마운트 될 때, 페이지 이동 시
            if (timerId) clearTimeout(timerId);
        };
    }, [timerId]);

    return (
        <div style={{ padding: 20 }}>
            <h1>Throttling / Debouncing Example</h1>

            <button onClick={() => throttle(2000)}>Throttle 버튼</button>
            <button onClick={() => debounce(2000)}>Debounce 버튼</button>
        </div>
    );
};

export default Home;

💡 lodash

  • JavaScript 유틸리티 라이브러리로, 배열, 객체, 문자열 등의 데이터 조작을 쉽게 할 수 있는 다양한 함수들을 제공
  • 성능 최적화와 코드 가독성을 높이는 데 유용함. 특히 throttledebounce 같은 함수도 포함되어 있음

설치

npm i lodash
import { useState, useCallback } from "react";
import _ from "lodash";

function Home() {
  const [searchText, setSearchText] = useState("");
  const [inputText, setInputText] = useState("");

  const handleSearchText = _.debounce((text) => setSearchText(text), 2000);

  const handleChange = (e) => {
    setInputText(e.target.value);
    handleSearchText(e.target.value);
  };

  return (
    <div
      style={{
        paddingLeft: 20,
        paddingRight: 20,
      }}
    >
      <h1>디바운싱 예제</h1>
      <br />
      <input
        placeholder="입력값을 넣고 디바운싱 테스트를 해보세요."
        style={{ width: "300px" }}
        onChange={handleChange}
        type="text"
      />
      <p>Search Text: {searchText}</p>
      <p>Input Text: {inputText}</p>
    </div>
  );
}

export default Home;
  • ⚠️ 하지만 이 코드를 컴포넌트 내부에 그대로 쓰면 매 렌더링마다 debounce 함수가 새로 생성됨 → 디바운싱이 의도대로 동작하지 않음
    • 이를 방지하기 위해 useCallback으로 함수를 memoization
      const handleSearchText = useCallback(
          _.debounce((text) => setSearchText(text), 2000),
          []
      );

📌 인증(authentication)과 인가(authorization)

인증

  • 사용자가 등록된 회원인지 확인하는 과정 → 로그인 절차

인가

  • 인증된 사용자가 특정 리소스에 접근할 권한이 있는지 확인하는 과정 → 로그인 이후 권한 체크

💡 HTTP 프로토콜의 특징

  1. 무상태(stateless)
    • HTTP 요청 하나하나가 서로 독립적
    • 서버는 이전 요청 기록을 기억하지 않음
    • 로그인 상태 유지 같은 기능은 추가 장치(쿠키/토큰) 없이는 불가능
  2. 비연결성(connectionless)
    • 요청 → 응답 후 연결 바로 종료
    • 자원 절약에 좋지만 동일한 사용자 여부를 서버가 추적하기 어려움

💡 쿠키

  • 브라우저에 저장되는 작은 데이터 조각, key-value 형태로 저장
  • HTTP의 무상태성을 보완하여 사용자의 상태를 기억하는 역할
  • 서버가 응답 시 Set-Cookie 헤더로 쿠키를 내려주면, 브라우저가 자동 저장 (저장된 쿠키 정보는 개발자 도구 → 애플리케이션 → 저장용량 → 쿠키에서 확인할 수 있음)
  • 저장된 쿠키는 동일한 Origin(또는 CORS 허용된 Origin)에 요청할 때 자동으로 포함됨

쿠키 vs. lcoalStorage/sessionsStorage

항목쿠키localStorage / sessionStorage
저장 위치브라우저브라우저
서버 자동 전송OX
서버에서 설정 가능O (Set-Cookie)X (JS로만 조작)
주 사용처인증(session ID, token)일반 데이터

Origin & CORS

  • Origin = Protocol + Host + Port

    • 유튜브에서 받은 쿠키는 유튜브 Origin에서만 전송됨
  • CORS

    • Cross Origin Resource Sharing(CORS)는 다른 출처에 리소스 요청하는 것을 허용하는 정책
    • 브라우저는 보안상의 이유로 기본적으로 Same Origin Policy(SOP)를 원칙으로 하고 있지만, 서버와 클라이언트 각각 CORS 설정을 통해 상호합의된 웹사이트는 예외적으로 서로 다른 출처(Cross-Origin)임에도 API 요청이 가능함
  • 사용 예시

    • 세션 ID 보관
    • 자동 로그인 토큰
    • 간단한 사용자 정보 등

💡 세션

  • 서버가 로그인한 사용자 상태를 직접 저장·관리하는 방식
  • 로그인 성공 → 서버가 세션 생성
  • 브라우저에는 session ID만 쿠키로 전달

세션 + 쿠키 인증 방식

  • 로그인/회원가입 시 세션 인증

  • 로그인/회원가입 성공 시 세션에서 쿠키에 sessionid를 담아서 보냄

  • 세션 유지 상태: 서버에서 관리하는 세션 저장소에 회원 데이터가 있음

  • 세션 만료 상태 : 서버에서 관리하는 세션 저장소에 회원데이터 없음

  • 인가 필요한 API 요청/응답

  • 서버는 인가가 필요한 API 요청을 받으면 클라이언트 쿠키에 들어 있는 sessionid를 세션 저장소에 조회하고, 있으면 DB에 데이터를 조회하고 응답함

세션 방식의 한계

  1. 확장성 문제
    • 세션이 서버 메모리/스토리지에 저장됨
    • 서버 여러 대(멀티 서버) 환경에서는 → 세션 공유/동기화가 필요해 구조가 복잡해짐
  2. 메모리 부담 증가
    • 사용자 수 증가 = 서버 메모리 사용량 증가
  3. 서버가 상태를 가짐
    • RESTful 철학(Stateless)과 맞지 않음
    • 서버 리소스 의존도 증가
  4. 보안 문제 (세션 하이재킹)
    • session ID 탈취되면 공격자가 사용자를 가장 가능

→ 이런 한계들을 보안하기 위해 등장한 게 토큰 기반 인증, JWT(JSON Web Token) 기반 인증


💡 토큰

  • 인증 정보를 클라이언트가 직접 보관
  • 서버는 토큰 검증만 하면 되므로 무상태(stateless) 유지 가능
  • 확장성과 분산 환경에 강함
  • 실제 서비스에서는 JWT(JSON Web Token) 형식의 토큰을 가장 많이 사용

💡 암호화 vs. 인코딩 차이

구분암호화(Encryption)인코딩(Encoding)
목적보안전달/저장 편의
특징키가 있어야 복호화 가능누구나 복원 가능
사용 예비밀번호, 민감 정보 보호Base64, URL 인코딩

💡 JWT(JSON Web Token)

  • 토큰 기반 인증 방식에서 가장 널리 쓰이는 표준 포맷
  • 로그인 성공 → 서버가 JWT 생성 후 클라이언트에 전달 → 이후 요청마다 JWT를 전송하여 인증 처리

JWT 세 부분

  1. 헤더(Header)
    • 서명 알고리즘(HMAC, SHA256 등)
    • 토큰 타입(JWT)
  2. 본문(Payload)
    • 실제 데이터(사용자 정보, 만료 시간 등)
    • 누구나 디코딩 가능 → 민감 정보 저장 금지
  3. 서명(Signature)
    • Header + Payload를 secret key로 서명한 값
    • 토큰이 중간에 변조되지 않았음을 검증하는 역할

🔗 https://www.jwt.io/

JWT 주요 특징

  1. 국제 표준 규격 → 다양한 언어/플랫폼에서 사용 가능

  2. Payload는 누구나 디코딩해서 읽을 수 있음 → 기밀 보호용이 아니라 위조 방지용

  3. 서버만 알고 있는 secret key가 있어야 signature 검증 가능

    → 이 키가 일치해야 토큰이 조작되지 않았다는 걸 확인할 수 있음


0개의 댓글