기본 콘텐츠로 건너뛰기

비동기 처리(Promise/Async)

JAVASCRIPT / ASYNC

자바스크립트 비동기 처리 정복: 콜백 지옥에서 Async/Await까지

싱글 스레드 언어인 JavaScript가 서버 통신과 같은 무거운 작업을 멈춤 없이 처리하는 비결을 알아봅니다. Callback, Promise, 그리고 Async/Await로 이어지는 비동기 처리 패턴의 진화 과정을 실무 코드로 정리했습니다.

1. 싱글 스레드와 비동기(Asynchronous)의 필요성

자바스크립트는 기본적으로 싱글 스레드(Single Thread) 언어입니다. 즉, 한 번에 하나의 작업만 처리할 수 있습니다. 만약 서버에서 1GB짜리 데이터를 받아오는 작업을 동기(Synchronous)로 처리한다면, 다운로드가 끝날 때까지 브라우저는 멈춰버리고(Freezing) 사용자는 아무것도 할 수 없게 됩니다.

이러한 문제를 해결하기 위해 자바스크립트는 비동기(Asynchronous) 모델을 채택했습니다. 무거운 작업(서버 요청, 타이머 등)은 브라우저의 Web API에게 위임하고, 다음 코드를 즉시 실행합니다. 작업이 끝나면 이벤트 루프(Event Loop)가 결과를 다시 메인 스레드로 가져와 실행하는 방식입니다.

2. 과거의 유산: 콜백(Callback)과 콜백 지옥

ES6 이전에는 비동기 작업 후 특정 로직을 수행하기 위해 함수의 인자로 함수를 넘겨주는 콜백(Callback) 패턴을 사용했습니다. 하지만 비동기 작업이 연속적으로 필요할 경우, 코드가 옆으로 누운 피라미드 모양이 되며 가독성이 극도로 나빠지는 현상이 발생합니다.

// 가독성이 떨어지는 '콜백 지옥' 예시
loginUser(id, password, (user) => {
    getUserRoles(user, (roles) => {
        getAccessLevel(roles, (level) => {
            // ... 계속되는 중첩 ...
            console.log(level);
        });
    });
});

3. 모던 JS의 표준: 프로미스(Promise)의 등장

ES6(2015)에서 도입된 Promise는 비동기 작업의 최종 완료 또는 실패를 나타내는 객체입니다. 콜백 지옥을 해결하고, 비동기 처리를 더 직관적으로 체이닝(Chaining)할 수 있게 해줍니다.

Promise는 다음 3가지 상태 중 하나를 가집니다.

  • Pending (대기): 처리가 완료되지 않은 초기 상태
  • Fulfilled (이행): 처리가 성공적으로 완료됨 (resolve 호출)
  • Rejected (거부): 처리가 실패함 (reject 호출)
function loginUser(id, password) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (id === 'admin') resolve({ name: '관리자' });
            else reject(new Error('로그인 실패'));
        }, 1000);
    });
}

// .then()을 이용한 깔끔한 체이닝
loginUser('admin', '1234')
    .then(user => {
        console.log(`${user.name}님 환영합니다.`);
        return getUserRoles(user); // 다음 Promise 반환
    })
    .then(roles => console.log(roles))
    .catch(error => console.error(error)); // 에러 통합 처리

4. 궁극의 가독성: Async / Await 패턴

ES8(2017)에 도입된 async/await는 Promise를 기반으로 동작하지만, 문법적으로는 마치 동기 코드처럼 작성할 수 있게 해주는 문법적 설탕(Syntactic Sugar)입니다.

  • 함수 앞에 async를 붙이면 해당 함수는 항상 Promise를 반환합니다.
  • await 키워드는 Promise가 처리될 때까지 기다렸다가 결과를 반환합니다. (async 함수 내부에서만 사용 가능)
async function processLogin() {
    try {
        const user = await loginUser('admin', '1234'); // 기다림
        const roles = await getUserRoles(user);        // 기다림
        console.log('최종 권한:', roles);
    } catch (error) {
        // 동기 코드처럼 try-catch로 에러 처리 가능
        console.error('에러 발생:', error);
    }
}

5. [실전] Fetch API로 사용자 데이터 조회하기

실제 웹 개발에서 가장 많이 사용하는 패턴입니다. 외부 API에서 데이터를 가져와 화면에 표시하는 로직을 Async/Await를 사용해 구현해 보겠습니다.

async function fetchUserData(userId) {
    const url = `https://jsonplaceholder.typicode.com/users/${userId}`;
    
    try {
        // 1. 서버에 데이터 요청 (비동기)
        const response = await fetch(url);
        
        // 2. HTTP 상태 코드 확인
        if (!response.ok) {
            throw new Error(`HTTP Error: ${response.status}`);
        }

        // 3. JSON 파싱 (비동기)
        const userData = await response.json();
        
        console.log('사용자 정보:', userData);
        return userData;

    } catch (error) {
        console.error('데이터 조회 실패:', error.message);
    }
}

// 실행
fetchUserData(1);

💡 핵심 요약: 현대 자바스크립트 개발에서 비동기 처리는 선택이 아닌 필수입니다. Promise로 비동기의 흐름을 제어하고, Async/Await로 코드의 가독성을 높여 유지보수하기 쉬운 코드를 작성하세요.

댓글

이 블로그의 인기 게시물

Java Servlet Request Parameter 완전 정복 — GET/POST 모든 파라미터 확인 & 디버깅 예제 (Request Parameter 전체보기)

Java Servlet Request Parameter 완전 정복 — GET/POST 모든 파라미터 확인 & 디버깅 예제 Java Servlet Request Parameter 완전 정복 웹 애플리케이션에서 클라이언트로부터 전달되는 Request Parameter 를 확인하는 것은 필수입니다. 이 글에서는 Java Servlet 과 JSP 에서 GET/POST 요청 파라미터를 전체 출력하고 디버깅하는 방법을 다양한 예제와 함께 소개합니다. 1. 기본 예제: getParameterNames() 사용 Enumeration<String> params = request.getParameterNames(); System.out.println("----------------------------"); while (params.hasMoreElements()){ String name = params.nextElement(); System.out.println(name + " : " + request.getParameter(name)); } System.out.println("----------------------------"); 위 코드는 요청에 포함된 모든 파라미터 이름과 값을 출력하는 기본 방법입니다. 2. HTML Form과 연동 예제 <form action="CheckParamsServlet" method="post"> 이름: <input type="text" name="username"><br> 이메일: <input type="email" name="email"><b...

PostgreSQL 달력(일별,월별)

SQL 팁: GENERATE_SERIES로 일별, 월별 날짜 목록 만들기 SQL 팁: GENERATE_SERIES 로 일별, 월별 날짜 목록 만들기 데이터베이스에서 통계 리포트를 작성하거나 비어있는 날짜 데이터를 채워야 할 때, 특정 기간의 날짜 목록이 필요할 수 있습니다. PostgreSQL과 같은 데이터베이스에서는 GENERATE_SERIES 함수를 사용하여 이 작업을 매우 간단하게 처리할 수 있습니다. 1. 🗓️ 일별 날짜 목록 생성하기 2020년 1월 1일부터 12월 31일까지의 모든 날짜를 '1 day' 간격으로 생성하는 쿼리입니다. WITH date_series AS ( SELECT DATE(GENERATE_SERIES( TO_DATE('2020-01-01', 'YYYY-MM-DD'), TO_DATE('2020-12-31', 'YYYY-MM-DD'), '1 day' )) AS DATE ) SELECT DATE FROM date_series 이 쿼리는 WITH 절(CTE)을 사용하여 date_series 라는 임시 테이블을 만들고, GENERATE_SERIES 함수로 날짜를 채웁니다. 결과 (일별 출력) 2. 📅 월별 날짜 목록 생성하기 동일한 원리로, 간격을 '1 MONTH' 로 변경하면 월별 목록을 생성할 수 있습니다. TO...

CSS로 레이어 팝업 화면 가운데 정렬하는 방법 (top·left·transform 완전 정리)

레이어 팝업 센터 정렬, 이 코드만 알면 끝 (CSS 예제 포함) 이벤트 배너나 공지사항을 띄울 때 레이어 팝업(center 정렬) 을 깔끔하게 잡는 게 생각보다 어렵습니다. 화면 크기가 변해도 가운데에 고정되고, 모바일에서도 자연스럽게 보이게 하려면 position , top , left , transform 을 정확하게 이해해야 합니다. 이 글에서는 아래 내용을 예제로 정리합니다. 레이어 팝업(center 정렬)의 기본 개념 자주 사용하는 position: absolute / fixed 정렬 방식 질문에서 주신 스타일 top: 3.25%; left: 50%; transform: translateX(-50%) 의 의미 실무에서 바로 쓰는 반응형 레이어 팝업 HTML/CSS 예제 1. 레이어 팝업(center 정렬)이란? 레이어 팝업(레이어 팝업창) 은 새 창을 띄우는 것이 아니라, 현재 페이지 위에 div 레이어를 띄워서 공지사항, 광고, 이벤트 등을 보여주는 방식을 말합니다. 검색엔진(SEO) 입장에서도 같은 페이지 안에 HTML이 존재 하기 때문에 팝업 안의 텍스트도 정상적으로 인덱싱될 수 있습니다. 즉, “레이어 팝업 센터 정렬”, “레이어 팝업 만드는 방법”과 같이 관련 키워드를 적절히 넣어주면 검색 노출에 도움이 됩니다. 2. 질문에서 주신 레이어 팝업 스타일 분석 질문에서 주신 스타일은 다음과 같습니다. <div class="layer-popup" style="width:1210px; z-index:9001; position:absolute; top:3.25%; left:50%; transform:translateX(-50%);"> 레이어 팝업 내용 <...