13. 시간을 다루는 마법 (비동기 처리)/13.3 약속을 지키는 Promise

13.3.2 Promise의 세 친구들 - then, catch, finally

thejavascript4kids 2025. 7. 18. 04:14

📘 13.3.2 Promise의 세 친구들 - then, catch, finally

여러분과 함께하는 이 시간이 참 소중하게 느껴집니다. 지난 시간 Promise의 첫 발걸음을 떼었다면, 이제는 그 Promise가 우리에게 전해주는 결과를 어떻게 받아들일지를 배워볼 차례입니다.

Promise에는 세 명의 든든한 친구들이 있습니다. then, catch, finally라는 이름을 가진 이들은 각각의 역할이 있어서, 마치 계절이 바뀌듯 자연스럽게 우리를 도와줍니다. 시험을 보고 난 후 결과를 기다리는 마음처럼, 우리도 미리 준비해 둔 마음가짐으로 그 결과를 맞이할 수 있습니다.

🧠 새로운 단어들과 친해지기

단어 쉬운 설명
then Promise가 성공했을 때 실행되는 기능이에요
catch Promise가 실패했을 때 실행되는 기능이에요
finally 성공/실패와 관계없이 항상 마지막에 실행되는 기능이에요
체이닝 이 기능들을 점(.)으로 연결해서 연속으로 사용하는 방법이에요

✨ then, catch, finally의 핵심 개념

then, catch, finally는 Promise의 결과를 처리하는 세 가지 주요 방법입니다.

  • then: Promise가 성공했을 때 실행됩니다 (resolve() 호출 시)
  • catch: Promise가 실패했을 때 실행됩니다 (reject() 호출 시)
  • finally: 성공하든 실패하든 상관없이 항상 마지막에 실행됩니다

정말 아름다운 점은 이 세 방법을 체이닝으로 연결할 수 있다는 것입니다. 강물이 자연스럽게 흘러가듯 .then().catch().finally() 형태로 이어서 사용할 수 있습니다.

따뜻한 비유: 온라인 게임 대회 참가 이야기

여러분이 좋아하는 온라인 게임 대회에 참가 신청을 했다고 상상해보세요. 대회 결과에 따라 미리 마음의 준비를 해둡니다.

  • "우승하면 → 친구들과 기쁨을 나누고 좋아하는 음식을 먹기"then
  • "아쉽게 탈락하면 → 마음을 다독이며 다음 대회를 위해 더 열심히 연습하기"catch
  • "우승하든 탈락하든 → 부모님께 결과를 알려드리고 하루를 마무리하기"finally

실제 게임 대회가 끝나면, 여러분이 미리 마음에 품어둔 이 계획들이 결과에 따라 자연스럽게 실행되는 것과 같습니다.

🎯 왜 이 세 방법을 사용할까요?

  1. 체계적인 결과 처리: 성공, 실패, 완료를 각각 명확하게 처리할 수 있습니다
  2. 코드 읽기 쉬움: 어떤 상황에서 무엇을 할지 쉽게 이해할 수 있습니다
  3. 오류 처리 간소화: 모든 종류의 오류를 catch 하나로 처리할 수 있습니다
  4. 재사용 가능한 구조: 같은 Promise에 대해 여러 가지 처리 방법을 적용할 수 있습니다

⚙️ 기본 사용법 살펴보기

기본 구조:

somePromise
    .then(function(성공결과) {
        console.log("성공:", 성공결과);
        // 성공했을 때 할 일
    })
    .catch(function(오류정보) {
        console.log("실패:", 오류정보);
        // 실패했을 때 할 일
    })
    .finally(function() {
        console.log("완료");
        // 항상 마지막에 할 일
    });

중요한 특징들:

  • then: 첫 번째 매개변수로 성공 결과를 받습니다
  • catch: 첫 번째 매개변수로 오류 정보를 받습니다
  • finally: 매개변수를 받지 않습니다 (결과와 무관하므로)

🧪 예제로 익혀보기

🔹 예제 1: 기본적인 then, catch, finally 사용법

// 동전 던지기 게임 (50% 확률로 성공/실패)
let coinFlipPromise = new Promise(function(resolve, reject) {
    console.log("동전을 던지고 있어요...");

    setTimeout(function() {
        let isHeads = Math.random() > 0.5;

        if (isHeads) {
            resolve("앞면이 나왔어요! 이겼어요!");
        } else {
            reject("뒷면이 나왔어요. 졌네요.");
        }
    }, 2000);
});

// 결과 처리
coinFlipPromise
    .then(function(승리메시지) {
        console.log("🎉 승리:", 승리메시지);
        console.log("축하 파티를 준비해요!");
    })
    .catch(function(패배메시지) {
        console.log("😢 패배:", 패배메시지);
        console.log("다음 기회에 다시 도전해봐요!");
    })
    .finally(function() {
        console.log("🎮 게임이 완전히 끝났어요.");
        console.log("동전을 정리하고 다른 게임을 준비해요.");
    });

console.log("게임이 진행되는 동안 다른 일을 할 수 있어요!");

🔹 예제 2: 사용자 로그인 처리하기

// 사용자 로그인을 처리하는 Promise 함수
function loginUser(username, password) {
    return new Promise(function(resolve, reject) {
        console.log(username + "님의 로그인을 시도해요...");

        setTimeout(function() {
            if (username === "student" && password === "1234") {
                resolve({
                    username: username,
                    message: "로그인에 성공했어요!",
                    loginTime: new Date().toLocaleTimeString()
                });
            } else {
                reject("아이디 또는 비밀번호가 틀렸어요.");
            }
        }, 1500);
    });
}

// 로그인 시도하고 결과 처리하기
loginUser("student", "1234")
    .then(function(사용자정보) {
        console.log("✅ 로그인 성공!");
        console.log("환영해요, " + 사용자정보.username + "님!");
        console.log("로그인 시간: " + 사용자정보.loginTime);
        console.log("메인 페이지로 이동해요...");
    })
    .catch(function(오류메시지) {
        console.log("❌ 로그인 실패:");
        console.log(오류메시지);
        console.log("다시 시도해주세요.");
        console.log("로그인 폼을 다시 보여줘요.");
    })
    .finally(function() {
        console.log("📝 로그인 시도가 기록되었어요.");
        console.log("로딩 화면을 제거해요.");
    });

🔹 예제 3: Promise 체이닝으로 여러 작업 연결하기

// 첫 번째 단계: 재료 준비
function prepareIngredients() {
    return new Promise(function(resolve) {
        console.log("🥕 요리 재료를 준비하고 있어요...");
        setTimeout(function() {
            resolve("신선한 재료들이 준비되었어요!");
        }, 1000);
    });
}

// 두 번째 단계: 요리하기
function cookFood(ingredients) {
    return new Promise(function(resolve, reject) {
        console.log("🍳 요리를 시작해요:", ingredients);
        setTimeout(function() {
            let cookingSuccess = Math.random() > 0.3; // 70% 성공 확률

            if (cookingSuccess) {
                resolve("맛있는 요리가 완성되었어요!");
            } else {
                reject("요리 중 실수가 있었어요!");
            }
        }, 2000);
    });
}

// 전체 요리 과정 실행
prepareIngredients()
    .then(function(재료준비결과) {
        console.log("✅ 재료 준비 완료:", 재료준비결과);
        return cookFood(재료준비결과); // 다음 단계로 전달
    })
    .then(function(요리결과) {
        console.log("🎉 요리 성공:", 요리결과);
        console.log("맛있게 드세요!");
    })
    .catch(function(오류) {
        console.log("😅 문제 발생:", 오류);
        console.log("치킨을 주문해요!");
    })
    .finally(function() {
        console.log("🧹 주방을 정리하고 설거지를 해요.");
        console.log("요리 과정이 모두 끝났어요.");
    });

🔄 then, catch, finally 실행 순서 정리하기

  1. Promise 실행: Promise가 시작되어 비동기 작업 수행 (Pending 상태)
  2. 결과 기다리기: Promise 내부에서 작업이 진행되는 동안 다른 코드들 실행
  3. then 또는 catch 실행: 성공 시 then, 실패 시 catch 중 하나만 실행
  4. finally 실행: then이나 catch가 실행된 후에 항상 실행
  5. 완료: 모든 처리가 끝나고 Promise 체인 종료

🧠 자주 하는 실수와 주의할 점

❌ 실수 1: catch 없이 then만 사용하기

// 위험한 예시 - 오류 처리가 없어요
somePromise
    .then(function(result) {
        console.log("성공:", result);
        // 만약 오류가 발생하면 처리할 방법이 없어요!
    });

// 안전한 예시
somePromise
    .then(function(result) {
        console.log("성공:", result);
    })
    .catch(function(error) {
        console.log("오류 발생:", error);
        console.log("문제를 해결하고 다시 시도해주세요.");
    });

❌ 실수 2: then에서 값을 반환하지 않아서 체이닝이 제대로 안 되는 경우

// 문제가 되는 예시
firstPromise
    .then(function(result) {
        console.log("첫 번째 결과:", result);
        // return을 하지 않았어요!
        "처리된 데이터"; // 이 값은 사라져요
    })
    .then(function(result) {
        console.log("두 번째 결과:", result); // undefined가 출력돼요
    });

// 올바른 예시
firstPromise
    .then(function(result) {
        console.log("첫 번째 결과:", result);
        return "처리된 데이터"; // 다음 then으로 전달
    })
    .then(function(result) {
        console.log("두 번째 결과:", result); // "처리된 데이터"가 출력돼요
    });

❌ 실수 3: finally에서 결과값을 사용하려고 시도하기

// 잘못된 예시 - finally는 결과값을 받지 않아요
somePromise
    .then(function(result) {
        return result + " 처리 완료";
    })
    .catch(function(error) {
        return "오류가 처리됨";
    })
    .finally(function(result) {
        console.log("최종 결과:", result); // undefined가 출력돼요!
    });

// 올바른 예시 - finally는 정리 작업만
somePromise
    .then(function(result) {
        console.log("성공 결과:", result);
        return result;
    })
    .catch(function(error) {
        console.log("오류:", error);
        return "기본값";
    })
    .finally(function() {
        console.log("작업이 완전히 끝났어요."); // 정리 작업만
        console.log("리소스를 정리해요.");
    });

✏️ 연습문제로 개념 다지기

연습문제를 시작하기 전에 잠시 멈춰 서보겠습니다. 지금까지 배운 Promise의 세 친구들이 여러분의 마음속에 어떻게 자리 잡았는지요. then은 기쁨을 나누는 친구처럼, catch는 아픔을 달래주는 친구처럼, finally는 언제나 곁에 있어주는 친구처럼 느껴지지 않나요. 이제 그 친구들과 함께 작은 연습을 해보겠습니다.

Ex1) 주사위 게임에서 4 이상이 나오면 성공, 그 외에는 실패하는 Promise 처리

let diceGame = new Promise(function(resolve, reject) {
    let diceNumber = Math.floor(Math.random() * 6) + 1;

    if (diceNumber >= 4) {
        resolve("주사위: " + diceNumber + " - 성공!");
    } else {
        reject("주사위: " + diceNumber + " - 실패!");
    }
});

diceGame
    .then(function(성공메시지) {
        console.log("🎉 축하해요!", 성공메시지);
        console.log("상품을 받아가세요!");
    })
    .catch(function(실패메시지) {
        console.log("😢 아쉬워요!", 실패메시지);
        console.log("다음 기회에 다시 도전해보세요!");
    })
    .finally(function() {
        console.log("🎮 게임이 끝났어요.");
        console.log("주사위를 정리해요.");
    });

Ex2) 나이 확인 Promise 함수

function checkAge(age) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            if (age >= 0 && age <= 150) {
                resolve("나이 확인 완료: " + age + "세");
            } else {
                reject("올바르지 않은 나이예요: " + age);
            }
        }, 1000);
    });
}

checkAge(15)
    .then(function(message) {
        console.log("✅ 성공:", message);
        console.log("서비스를 이용하실 수 있어요.");
    })
    .catch(function(error) {
        console.log("❌ 오류:", error);
        console.log("나이를 다시 확인해주세요.");
    })
    .finally(function() {
        console.log("📋 나이 확인 과정이 완료되었어요.");
    });

🤔 심화 문제로 실력 확인하기

Q1. then, catch, finally가 실행되는 순서와 조건을 설명해보세요.

정답: Promise의 결과에 따라 then(성공 시) 또는 catch(실패 시) 중 하나가 먼저 실행되고, 그 다음에 finally가 항상 실행됩니다.

Q2. 다음 코드의 출력 순서를 예측해보세요.

console.log("1");
Promise.resolve("성공")
    .then(function(result) {
        console.log("2:", result);
    })
    .finally(function() {
        console.log("3");
    });
console.log("4");

정답: "1" → "4" → "2: 성공" → "3"

해설: 먼저 동기 코드인 "1"과 "4"가 출력되고, 그 후 Promise가 처리되어 then과 finally가 순서대로 실행됩니다.

Q3. Promise 체이닝에서 then이 여러 개 연결될 때 어떻게 값이 전달되나요?

정답: 각 then에서 return한 값이 다음 then의 매개변수로 전달됩니다. return을 하지 않으면 undefined가 전달됩니다.

🔙 지난 시간 복습하기 (13.3.1 - Promise 기본)

복습 문제 1: Promise의 세 가지 상태 중 틀린 것은?

A) Pending (대기 중)
B) Fulfilled (성공 완료)
C) Processing (처리 중)
D) Rejected (실패)

정답: C) Processing (처리 중)

복습 문제 2: Promise 생성자 함수의 매개변수는?

정답: resolvereject

Promise의 세 친구들인 then, catch, finally를 잘 활용하면 복잡한 비동기 작업도 차분하고 안전하게 처리할 수 있습니다. 다음 시간에는 이런 Promise들을 더 효과적으로 연결하는 고급 기법들을 배워보겠습니다.

✅ 학습 완료 체크리스트

학습 내용 이해했나요?
then, catch, finally의 역할
기본 사용법과 체이닝
실행 순서와 조건
자주 하는 실수들
실전 예제 만들기

🎯 추가 연습 문제들

여러분이 더 깊이 이해하고 싶어 하는 마음이 느껴집니다. 추가 연습문제들을 통해 그 마음에 응답하겠습니다.

추가 문제 1. 성공/실패를 처리하는 간단한 Promise

let randomPromise = new Promise(function(resolve, reject) {
    if (Math.random() > 0.5) {
        resolve("성공!");
    } else {
        reject("실패!");
    }
});

randomPromise
    .then(function(result) {
        console.log("좋아요!", result);
    })
    .catch(function(error) {
        console.log("아쉬워요!", error);
    })
    .finally(function() {
        console.log("게임 끝");
    });

추가 문제 2. 환영 메시지 Promise

function greetUser(name) {
    return new Promise(function(resolve, reject) {
        if (name && name.length > 0) {
            resolve("환영합니다, " + name + "님!");
        } else {
            reject("이름을 입력해주세요");
        }
    });
}

greetUser("철수")
    .then(function(message) {
        console.log(message);
    })
    .catch(function(error) {
        console.log("에러:", error);
    })
    .finally(function() {
        console.log("인사 처리 완료");
    });

📂 마무리 정보

오늘 배운 Promise의 세 친구들이 여러분의 자바스크립트 지식에 잘 스며들었나요? 다음 시간에는 Promise를 더 효과적으로 사용하는 방법들을 배워볼 예정입니다.


🚀 더 체계적인 JavaScript 학습을 원하신다면?
이 포스팅에서 다룬 내용을 실제로 실습해보세요!
무료 JavaScript 학습 플랫폼에서 단계별 학습과 실시간 코드 실행을 통해
더욱 효과적이고 재미있게 학습하실 수 있습니다.
📝 실시간 코드 실행 📊 학습 진도 관리 👥 체계적 커리큘럼
📚 171개 체계적 학습레슨 · 📋 855개 4지선다 연습문제 · 🆓 완전 무료 · ⚡ 즉시 시작