13. 시간을 다루는 마법 (비동기 처리)/13.5 fetch로 데이터 불러오기

13.5.1 fetch - 인터넷에서 정보 가져오는 도구

thejavascript4kids 2025. 7. 19. 05:24

📘 13.5.1 fetch - 인터넷에서 정보 가져오는 도구

안녕하세요, 여러분. 지금까지 우리가 함께 걸어온 길을 돌아보니, 참으로 많은 것들을 배웠습니다. Promise의 약속과 기다림, async/await의 아름다운 기다림의 문법까지. 마치 씨앗을 심고 물을 주며 기다리는 정원사처럼, 우리는 시간의 흐름 속에서 순서가 있는 일들을 다루는 방법을 천천히 익혀왔어요.

이제는 그 모든 배움이 꽃을 피우는 순간입니다. 바로 fetch라는 도구를 만나볼 차례예요. 이 작은 도구는 인터넷이라는 넓은 바다에서 우리가 필요한 정보를 조용히 가져와 줍니다. 마치 멀리 있는 친구에게 편지를 보내고 답장을 받는 것처럼, 서버라는 먼 곳에 있는 정보를 우리 웹페이지로 불러올 수 있게 해주는 소중한 기능이지요.

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

fetch와 함께하는 여행에서 만날 단어들을 살펴보겠습니다.

단어 의미
fetch 인터넷을 통해 다른 곳에서 정보를 가져오는 자바스크립트의 기능입니다.
API 다른 프로그램이나 서버와 정보를 주고받을 수 있는 방법이나 약속을 뜻해요.
인터넷 요청 인터넷을 통해 다른 컴퓨터에게 정보나 서비스를 요청하는 것을 말합니다.
응답 정보 서버가 우리의 요청에 대해 보내주는 답장 정보를 의미해요.

fetch라는 단어가 영어로 "가져오다"를 뜻하는 것처럼, 실제로도 먼 곳에 있는 정보를 우리에게 가져다주는 역할을 합니다.

✨ fetch의 핵심 개념

fetch는 현대 웹 개발에서 가장 소중한 기능 중 하나로, 인터넷을 통해 다른 서버에서 정보를 가져오는 표준적인 방법입니다. 예전에는 XMLHttpRequest라는 복잡한 방법을 사용했지만, fetch는 훨씬 더 간단하고 이해하기 쉬워졌어요.

fetch의 가장 아름다운 점은 Promise를 돌려준다는 것입니다. 그래서 지금까지 우리가 배운 async/await나 then/catch를 그대로 사용할 수 있어요. 마치 우리가 배운 모든 기술들이 이 순간을 위해 준비되었던 것처럼 자연스럽게 연결됩니다.

fetch의 작동 과정은 우리 일상과 참 닮아있어요. 우리가 fetch에게 "이 주소에서 정보를 가져다 주세요"라고 부탁하면, fetch가 인터넷을 통해 그 주소로 가서 정보를 요청하고, 서버에서 답장을 받아서 우리에게 전해줍니다.

기억해야 할 특징은 fetch가 네트워크 작업이므로 시간이 걸린다는 것입니다. 그래서 항상 기다리면서 처리해야 하고, Promise나 async/await를 사용해야 해요. 또한 서버에서 받은 답장을 바로 사용할 수는 없고, .json() 같은 방법으로 변환해야 합니다.

실용적인 활용으로는 날씨 정보 가져오기, 뉴스 헤드라인 보여주기, 사용자 프로필 정보 불러오기, 실시간 정보 업데이트 등이 있어요. 현대 웹사이트의 거의 모든 동적 기능이 fetch를 기반으로 구현됩니다.

따뜻한 비유: 도서관에서 책 빌리기

fetch를 더 쉽게 이해하기 위해 '도서관에서 책 빌리기'에 비유해보겠습니다.

여러분이 도서관에 가서 특정한 책을 빌리고 싶다고 생각해보세요.

1단계 - 사서님께 요청하기 (fetch 호출):
"혹시 'JavaScript 입문서' 있을까요?"라고 사서님께 정중히 물어봅니다. 이것이 바로 fetch('도서관주소/JavaScript입문서')와 같아요.

2단계 - 사서님이 찾아보기 (서버 처리):
사서님이 컴퓨터를 확인하고 서가를 둘러보며 책이 있는지 확인합니다. 이 시간 동안 여러분은 기다려야 해요. 마치 Promise가 기다리는 상태에 있는 것과 같지요.

3단계 - 답장 받기 (Response 객체):
사서님이 "네, 여기 있습니다"라고 말하며 책을 건네주거나, "죄송합니다, 대출 중입니다"라고 알려줍니다. 이것이 서버의 답장(Response)이에요.

4단계 - 책 내용 읽기 (.json() 처리):
책을 받았다고 해서 바로 내용을 아는 것은 아니에요. 책을 열어서 실제로 읽어야 내용을 알 수 있지요. 마찬가지로 서버 답장을 받았다고 해서 바로 정보를 사용할 수 있는 것이 아니라, .json()이나 .text() 같은 방법으로 "읽어야" 실제 정보를 얻을 수 있습니다.

이런 과정이 바로 fetch의 전체 작동 방식입니다.

🎯 fetch를 사용하는 이유

fetch가 왜 현대 웹 개발에서 이렇게 중요할까요? 여러 소중한 이유들이 있습니다.

첫 번째는 실시간 정보 업데이트입니다. 페이지를 새로고침하지 않고도 최신 정보를 가져올 수 있어요. 주식 가격, 날씨, 채팅 메시지 등이 실시간으로 업데이트되는 웹사이트들이 바로 fetch를 사용합니다.

두 번째는 사용자의 편의성입니다. 사용자가 버튼을 클릭하면 즉시 관련 정보를 보여줄 수 있어서, 빠르고 반응이 좋은 웹사이트를 만들 수 있어요. 마치 모바일 앱처럼 부드러운 경험을 제공할 수 있습니다.

세 번째는 외부 서비스 활용입니다. 다른 회사에서 제공하는 무료 API를 사용해서 우리 웹사이트에 풍부한 기능을 추가할 수 있어요. 예를 들어, 날씨 API로 날씨 정보를, 뉴스 API로 최신 뉴스를 가져올 수 있습니다.

네 번째는 정보 기반 웹사이트를 만들 수 있다는 점입니다. 서버에 저장된 사용자 정보, 상품 목록, 게시글 등을 동적으로 불러와서 보여줄 수 있어요.

마지막으로 현대적인 웹 개발 패턴을 따를 수 있습니다. 요즘 웹사이트는 거의 모두 fetch를 사용해서 구현되므로, fetch를 알아야 현대적인 웹 개발을 할 수 있어요.

⚙️ 기본 사용법 살펴보기

fetch의 기본 사용법은 우리가 배운 Promise와 async/await 패턴을 그대로 사용합니다.

기본 구조 (Promise 방식):

fetch('정보를_가져올_주소')
    .then(function(response) {
        // 서버 답장을 실제 정보로 변환
        return response.json();
    })
    .then(function(data) {
        // 변환된 정보 사용
        console.log(data);
    })
    .catch(function(error) {
        // 문제 처리
        console.log('문제가 발생했어요:', error);
    });

기본 구조 (async/await 방식):

async function getData() {
    try {
        let response = await fetch('정보를_가져올_주소');
        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.log('문제가 발생했어요:', error);
    }
}

중요한 단계들:

  1. fetch(URL): 서버에 정보 요청
  2. response.json(): 서버 답장을 JSON 정보로 변환
  3. 변환된 정보 사용
  4. 문제 처리

주의할 점:

  • fetch는 항상 Promise를 돌려주므로 await나 then을 사용해야 해요
  • response.json()도 Promise를 돌려주므로 다시 await나 then이 필요해요
  • 네트워크 문제뿐만 아니라 HTTP 문제도 확인해야 해요

🧪 예제로 익혀보기

실제 예제를 통해 fetch가 어떻게 작동하는지 단계별로 알아보겠습니다.

🔹 예제 1: 가장 기본적인 fetch 시뮬레이션

이번 예제에서는 실제 인터넷 연결 없이도 fetch의 작동 원리를 이해할 수 있도록 시뮬레이션 함수를 만들어보겠습니다.

// 가짜 서버 API를 시뮬레이션하는 함수
function simulateFetch(url) {
    return new Promise(function(resolve, reject) {
        console.log("📡 " + url + "에서 정보를 요청하고 있어요...");

        setTimeout(function() {
            if (url.includes("users")) {
                // 사용자 정보 시뮬레이션
                resolve({
                    ok: true,
                    json: function() {
                        return Promise.resolve({
                            name: "김학생",
                            age: 12,
                            grade: "5학년",
                            hobby: "독서"
                        });
                    }
                });
            } else if (url.includes("weather")) {
                // 날씨 정보 시뮬레이션
                resolve({
                    ok: true,
                    json: function() {
                        return Promise.resolve({
                            city: "서울",
                            temperature: 20,
                            condition: "맑음",
                            humidity: 60
                        });
                    }
                });
            } else {
                reject(new Error("알 수 없는 주소예요"));
            }
        }, 1000);
    });
}

// 시뮬레이션 fetch를 사용한 기본 예제
async function getSimpleUserInfo() {
    console.log("👤 사용자 정보를 가져오고 있어요");

    try {
        let response = await simulateFetch('https://api.example.com/users/1');

        if (response.ok) {
            let user = await response.json();

            console.log("✅ 사용자 정보 성공!");
            console.log("📝 이름:", user.name);
            console.log("🎂 나이:", user.age);
            console.log("🏫 학년:", user.grade);
            console.log("📚 취미:", user.hobby);

            return user;
        } else {
            throw new Error("사용자 정보를 가져올 수 없어요");
        }
    } catch (error) {
        console.log("❌ 문제가 발생했어요:", error.message);
        return null;
    }
}

// 함수 실행해보기
getSimpleUserInfo();

이 예제에서는 실제 인터넷 연결이 필요한 외부 API 대신 simulateFetch 함수를 만들어서 fetch의 작동 방식을 시뮬레이션했어요. 실제 fetch와 동일한 방식으로 Promise를 돌려주고, response.json() 메서드도 제공해서 실제 fetch 사용법을 완전히 익힐 수 있습니다.

🔹 예제 2: 여러 종류의 정보 가져오기

이번에는 다양한 종류의 정보를 가져와서 비교해보는 예제를 만들어보겠습니다.

// 날씨 정보 가져오기
async function getWeatherInfo() {
    console.log("🌤️ 날씨 정보를 확인하고 있어요");

    try {
        let response = await simulateFetch('https://api.weather.com/current');

        if (!response.ok) {
            throw new Error("날씨 서버에 문제가 있어요");
        }

        let weather = await response.json();

        console.log("✅ 날씨 정보 받아왔어요!");
        console.log("🏙️ 도시:", weather.city);
        console.log("🌡️ 온도:", weather.temperature + "도");
        console.log("☀️ 날씨:", weather.condition);
        console.log("💧 습도:", weather.humidity + "%");

        return weather;
    } catch (error) {
        console.log("❌ 날씨 정보 오류:", error.message);
        return null;
    }
}

// 여러 정보를 함께 가져오기
async function getAllInfo() {
    console.log("📊 모든 정보를 가져오기 시작!");

    try {
        // 사용자 정보와 날씨 정보를 차례대로 가져오기
        let user = await getSimpleUserInfo();
        let weather = await getWeatherInfo();

        if (user && weather) {
            console.log("\n🎉 모든 정보 수집 완료!");
            console.log("👋 " + user.name + "님, 안녕하세요!");
            console.log("📍 " + weather.city + "의 현재 온도는 " + weather.temperature + "도이고, " + weather.condition + "이에요.");

            // 날씨에 따른 추천 메시지
            if (weather.temperature > 25) {
                console.log("🌞 더운 날씨네요! 시원한 음료수를 마시세요.");
            } else if (weather.temperature < 10) {
                console.log("🧥 추운 날씨네요! 따뜻하게 입으세요.");
            } else {
                console.log("😊 좋은 날씨네요! 산책하기 좋을 것 같아요.");
            }
        }

        return { user, weather };
    } catch (error) {
        console.log("❌ 정보 수집 중 문제:", error.message);
        return null;
    }
}

// 전체 정보 가져오기 실행
getAllInfo();

이 예제에서는 여러 가지 종류의 정보를 차례대로 가져와서 조합하는 방법을 보여줍니다. 사용자 정보와 날씨 정보를 각각 가져와서 개인화된 메시지를 만들고, 날씨에 따른 추천까지 제공하는 실용적인 예제예요.

🔹 예제 3: 문제 상황 처리하기

실제 사용에서 발생할 수 있는 다양한 문제 상황을 처리하는 방법을 배워보겠습니다.

// 문제가 발생할 수 있는 시뮬레이션 함수
function unreliableFetch(url) {
    return new Promise(function(resolve, reject) {
        console.log("📡 " + url + "에 요청하고 있어요...");

        setTimeout(function() {
            let random = Math.random();

            if (random < 0.3) {
                // 30% 확률로 네트워크 오류
                reject(new Error("인터넷 연결이 불안정해요"));
            } else if (random < 0.5) {
                // 20% 확률로 서버 오류
                resolve({
                    ok: false,
                    status: 500,
                    json: function() {
                        return Promise.reject(new Error("서버에 문제가 있어요"));
                    }
                });
            } else {
                // 50% 확률로 성공
                resolve({
                    ok: true,
                    status: 200,
                    json: function() {
                        return Promise.resolve({
                            message: "성공적으로 정보를 가져왔어요!",
                            timestamp: new Date().toLocaleString(),
                            data: "중요한 정보들..."
                        });
                    }
                });
            }
        }, 1500);
    });
}

// 강건한 정보 가져오기 (재시도 기능 포함)
async function robustFetch(url, maxRetries = 3) {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        console.log(`🔄 ${attempt}번째 시도 중...`);

        try {
            let response = await unreliableFetch(url);

            if (response.ok) {
                let data = await response.json();
                console.log("✅ 성공! 정보:", data.message);
                console.log("⏰ 시간:", data.timestamp);
                return data;
            } else {
                console.log(`❌ 서버 문제 (상태: ${response.status})`);
                if (attempt === maxRetries) {
                    throw new Error("서버 문제로 정보를 가져올 수 없어요");
                }
            }
        } catch (error) {
            console.log(`❌ ${attempt}번째 시도 실패:`, error.message);

            if (attempt === maxRetries) {
                console.log("😞 모든 시도가 실패했어요");
                return null;
            } else {
                console.log("💪 다시 시도해보겠어요...");
                // 잠시 기다린 후 재시도
                await new Promise(resolve => setTimeout(resolve, 1000));
            }
        }
    }
}

// 강건한 fetch 테스트
robustFetch('https://api.example.com/important-data');

이 예제는 실제 인터넷 환경에서 발생할 수 있는 다양한 문제 상황들을 시뮬레이션하고, 이를 안전하게 처리하는 방법을 보여줍니다. 재시도 기능까지 포함해서 더욱 신뢰할 수 있는 fetch 사용법을 배울 수 있어요.

🔄 fetch 사용 과정 정리하기

지금까지 배운 fetch 사용 과정을 단계별로 정리해보겠습니다.

첫 번째 단계는 요청 보내기입니다. fetch(URL)을 사용해서 원하는 서버 주소에 정보를 요청해요. 이때 fetch는 즉시 Promise를 돌려주고 백그라운드에서 네트워크 작업을 시작합니다.

두 번째는 서버 답장 기다리기입니다. 서버가 요청을 처리하는 동안 우리 코드는 다른 일을 계속 할 수 있어요. Promise가 resolve되면 Response 객체를 받게 됩니다.

세 번째는 답장 상태 확인하기입니다. response.ok를 확인해서 요청이 성공했는지 검사해야 해요. HTTP 404나 500 같은 문제는 여전히 Promise가 resolve되므로 별도로 확인해야 합니다.

네 번째는 정보 변환하기입니다. response.json() 또는 response.text()를 사용해서 서버 답장을 실제로 사용할 수 있는 형태로 변환해요. 이 과정도 기다려야 하므로 await나 then이 필요합니다.

마지막으로 정보 사용하기입니다. 변환된 정보를 화면에 표시하거나 다른 처리를 하면 fetch 과정이 완료됩니다.

🧚‍♀️ 이야기로 다시 배우기: 택배 배송 서비스

지금까지 배운 내용을 하나의 이야기로 다시 정리해볼까요?

어느 작은 마을에 신속한 택배 배달부 페치가 있었습니다. 페치의 특별한 능력은 인터넷 택배를 사용해서 멀리 있는 상점들로부터 물건을 가져오는 것이었어요.

주문하기:
사람들이 "날씨 정보 상점에서 내일 날씨를 주문해 주세요"라고 부탁하면, 페치는 특별한 온라인 주문 시스템을 사용했습니다. fetch('날씨정보상점.com')처럼 말이죠.

배송 시간:
상점에서 물건을 준비하는 동안, 사람들은 다른 일을 계속할 수 있었습니다. 택배가 도착할 때까지 기다리면서도 다른 일을 할 수 있는 것이 온라인 주문의 장점이었지요.

택배 확인:
택배가 도착해서 "배송 완료!"라고 알림이 오면(response.ok), 페치는 택배 상자를 확인했습니다. 하지만 상자가 특별한 포장재로 싸여있어서 바로 내용물을 볼 수 없었어요.

포장 풀기:
페치는 "포장 풀기 도구"(response.json())를 사용해서 포장재를 제거했습니다. 그제서야 "내일은 맑고 기온은 20도입니다"라는 실제 정보를 얻을 수 있었답니다.

정보 전달:
마지막으로 페치는 포장을 푼 정보를 사람들에게 전해주었습니다. 사람들은 "와! 내일 소풍 가기 좋겠다!"라며 기뻐했답니다.

fetch도 이 택배 배달부 페치와 똑같은 방식으로 작동합니다. 멀리 있는 서버에 주문을 보내고, 답장을 받아서, 포장을 풀어서, 우리가 사용할 수 있게 만들어주는 편리한 배송 서비스예요!

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

fetch를 사용할 때 자주 실수하는 부분들을 미리 알아두면 더 안전한 코딩을 할 수 있습니다.

❌ 실수 1: response.json()에 await를 빼먹기

// 잘못된 예시 - await 빼먹음
async function wrongWay() {
    let response = await simulateFetch('https://api.example.com/data');
    let data = response.json(); // await가 없음!
    console.log(data); // Promise 객체가 출력됨
}

// 올바른 예시
async function rightWay() {
    let response = await simulateFetch('https://api.example.com/data');
    let data = await response.json(); // await 필수!
    console.log(data); // 실제 정보가 출력됨
}

이런 실수가 발생하는 이유는 response.json()도 Promise를 돌려주기 때문입니다. fetch()만 기다려야 한다고 생각하기 쉽지만, 실제로는 정보 변환 과정도 기다려야 하는 작업이에요.

❌ 실수 2: HTTP 문제 상태를 확인하지 않기

// 위험한 예시 - 404, 500 문제도 성공으로 처리됨
async function noStatusCheck() {
    try {
        let response = await simulateFetch('https://nonexistent-api.com/data');
        let data = await response.json(); // 404 문제여도 실행 시도
        console.log(data);
    } catch (error) {
        console.log("문제:", error); // 네트워크 문제만 잡힘
    }
}

// 안전한 예시
async function withStatusCheck() {
    try {
        let response = await simulateFetch('https://api.example.com/data');

        if (!response.ok) {
            throw new Error(`HTTP 문제: ${response.status}`);
        }

        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.log("문제:", error); // 모든 종류의 문제 처리
    }
}

fetch는 네트워크 문제(인터넷 연결 끊김 등)만 Promise를 reject하고, HTTP 문제(404, 500 등)는 여전히 Promise를 resolve합니다. 따라서 response.ok를 직접 확인해야 해요.

❌ 실수 3: 문제 처리 없이 fetch 사용하기

// 위험한 예시 - 문제 처리 전혀 없음
async function dangerousCode() {
    let response = await simulateFetch('https://unreliable-api.com/data');
    let data = await response.json();
    console.log("받은 정보:", data.message);
    // 네트워크 문제나 API 오류 시 앱이 멈출 수 있음
}

// 안전한 예시 - 완전한 문제 처리
async function safeCode() {
    try {
        let response = await simulateFetch('https://api.example.com/data');

        if (!response.ok) {
            throw new Error(`서버 문제: ${response.status}`);
        }

        let data = await response.json();
        console.log("받은 정보:", data.message);
    } catch (error) {
        console.log("정보 로딩 실패:", error.message);
        console.log("기본 메시지: 정보를 불러올 수 없어요. 잠시 후 다시 시도해주세요.");
    }
}

인터넷 연결이 불안정하거나 서버에 문제가 있을 수 있으므로, 항상 try/catch로 문제를 처리하고 사용자에게 적절한 메시지를 보여줘야 합니다.

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

여러분들이 혼자서도 충분히 걸어갈 수 있도록, 함께 연습해보겠습니다. 새로운 씨앗을 심는 마음으로 차근차근 시작해볼까요.

배운 내용을 연습문제를 통해 확실히 익혀보겠습니다.

Ex1) 사용자 정보를 가져와서 "안녕하세요, ○○님!"이라고 인사해보자

// 시뮬레이션 API 사용
async function greetUser() {
    try {
        console.log("👤 사용자 정보를 불러오고 있어요...");

        // 사용자 정보 요청하기
        let response = await simulateFetch('https://api.example.com/users/me');

        // 요청이 성공했는지 확인하기
        if (response.ok) {
            // JSON 정보로 변환하기
            let user = await response.json();
            // 친근한 인사 만들기
            let greeting = "안녕하세요, " + user.name + "님!";
            console.log("👋 " + greeting);
            return greeting;
        } else {
            console.log("❌ 요청 실패:", response.status);
            return "안녕하세요!";
        }
    } catch (error) {
        console.log("❌ 네트워크 문제:", error.message);
        return "안녕하세요! 좋은 하루 되세요!"; // 기본 인사
    }
}

// 함수 실행
greetUser();

Ex2) 날씨 정보를 가져와서 온도에 따른 옷차림 추천하기

async function recommendClothing() {
    try {
        console.log("🌤️ 날씨 정보를 확인하고 있어요...");

        // 날씨 정보 요청하기
        let response = await simulateFetch('https://api.weather.com/current');

        // 요청 성공 확인하기
        if (!response.ok) {
            throw new Error("날씨 정보를 가져올 수 없어요");
        }

        // JSON 정보로 변환하기
        let weather = await response.json();
        console.log("🌡️ 현재 온도:", weather.temperature + "도");

        // 온도에 따른 옷차림 추천
        let recommendation;
        if (weather.temperature > 25) {
            recommendation = "🌞 더운 날씨예요! 반팔과 반바지를 입으세요.";
        } else if (weather.temperature > 15) {
            recommendation = "😊 좋은 날씨예요! 긴팔 셔츠나 얇은 가디건이 좋겠어요.";
        } else if (weather.temperature > 5) {
            recommendation = "🧥 쌀쌀한 날씨예요! 자켓이나 후드티를 입으세요.";
        } else {
            recommendation = "🧤 추운 날씨예요! 따뜻한 외투와 장갑을 챙기세요.";
        }

        console.log("👔 추천:", recommendation);
        return recommendation;
    } catch (error) {
        console.log("❌ 날씨 정보 오류:", error.message);
        return "🤷‍♀️ 날씨 정보를 확인할 수 없어요. 적당히 입으세요!";
    }
}

recommendClothing();

Ex3) 여러 번 시도해서 정보를 안전하게 가져오기

async function safeDataFetch(url, maxRetries = 2) {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
            console.log(`🔄 ${attempt}번째 시도: ${url}`);

            // 정보 요청하기
            let response = await unreliableFetch(url);

            // 성공 확인하기
            if (response.ok) {
                let data = await response.json();
                console.log("✅ 성공! 메시지:", data.message);
                return data;
            } else {
                console.log(`❌ 서버 오류 (${response.status})`);
            }
        } catch (error) {
            console.log(`❌ ${attempt}번째 시도 실패:`, error.message);
        }

        // 마지막 시도가 아니면 잠시 기다리기
        if (attempt < maxRetries) {
            console.log("⏳ 1초 후 다시 시도해요...");
            await new Promise(resolve => setTimeout(resolve, 1000));
        }
    }

    console.log("😞 모든 시도가 실패했어요");
    return null;
}

// 안전한 데이터 가져오기 테스트
safeDataFetch('https://api.example.com/important-data');

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

기본 연습을 마쳤다면, 이제 조금 더 깊이 있는 문제들을 통해 fetch에 대한 이해를 확인해보겠습니다.

Q1. fetch가 돌려주는 것과 실제 정보를 얻는 과정을 설명해보세요.

정답: fetch는 Promise를 돌려주며, 이 Promise는 Response 객체로 resolve됩니다. Response 객체는 서버의 답장을 나타내지만 실제 정보가 아니에요. 실제 정보를 얻으려면 response.json()이나 response.text() 같은 방법을 사용해서 Response 객체를 실제 정보로 변환해야 합니다.

해설: 마치 편지봉투를 받은 것과 편지 내용을 읽는 것이 다른 것처럼, Response 객체를 받는 것과 실제 정보를 추출하는 것은 별도의 과정입니다. 이는 다양한 형태의 정보(JSON, 텍스트, 이미지 등)를 유연하게 처리하기 위한 설계예요.

Q2. fetch에서 문제 처리를 할 때 주의해야 할 점은 무엇인가요?

정답: fetch는 네트워크 문제(인터넷 연결 문제)만 Promise를 reject하고, HTTP 문제(404, 500 등)는 여전히 Promise를 resolve하므로 response.ok를 별도로 확인해야 합니다. 또한 response.json()이나 response.text()에서도 문제가 발생할 수 있으므로 전체 과정을 try/catch로 감싸야 해요.

해설: 이는 fetch의 설계 철학 때문인데, HTTP 문제도 "성공적인 통신"으로 간주하기 때문입니다. 따라서 개발자가 직접 답장 상태를 확인해서 비즈니스 로직상의 성공/실패를 판단해야 합니다.

Q3. 다음 코드에서 문제점을 찾고 올바른 코드로 수정해보세요.

async function getData() {
    let response = await simulateFetch('https://api.example.com/data');
    let data = response.json();
    console.log(data);
}

정답: response.json()에 await가 없어서 Promise 객체가 출력됩니다.

수정된 코드:

async function getData() {
    try {
        // 서버에서 정보 요청하기
        let response = await simulateFetch('https://api.example.com/data');

        // 요청 성공 확인하기
        if (!response.ok) {
            throw new Error(`HTTP 문제: ${response.status}`);
        }

        // JSON 정보로 변환하기 (await 추가!)
        let data = await response.json();
        console.log(data); // 실제 정보 출력
        return data;
    } catch (error) {
        console.log("문제:", error.message); // 문제 발생 시 처리
        return null;
    }
}

📝 이전 단원 복습하기

13.4.3에서 배운 Promise vs async/await 비교를 복습해볼까요?

복습 문제 1: async/await가 Promise보다 좋은 점 2가지를 설명해보세요.

정답: 1) 코드를 위에서 아래로 차례대로 읽을 수 있어서 이해하기 쉽습니다. 2) try/catch로 모든 에러를 한 곳에서 처리할 수 있어서 에러 관리가 편해요.

해설: async/await는 복잡한 Promise 체이닝을 일반 코드처럼 작성할 수 있게 해줘서, 특히 조건문이나 반복문이 포함된 복잡한 로직에서 큰 장점을 발휘합니다.

복습 문제 2: 다음 Promise 코드를 async/await로 변환해보세요.

문제:

function getData() {
    return simulateFetch('/api/data')
        .then(response => response.json())
        .then(data => {
            console.log("데이터:", data);
            return data;
        })
        .catch(error => {
            console.log("에러:", error);
            return null;
        });
}

정답:

async function getData() {
    try {
        let response = await simulateFetch('/api/data');
        let data = await response.json();
        console.log("데이터:", data);
        return data;
    } catch (error) {
        console.log("에러:", error);
        return null;
    }
}

해설: .then() 체이닝은 await로, .catch()는 try/catch로 변환하면 더 읽기 쉬운 코드가 됩니다. 이런 변환을 통해 fetch를 더 직관적으로 사용할 수 있어요.

지금까지 fetch의 기본 사용법을 배웠습니다. fetch는 현대 웹 개발에서 없어서는 안 될 중요한 도구로, 인터넷의 풍부한 정보를 우리 웹사이트에 가져올 수 있게 해줍니다. 다음 시간에는 fetch를 사용해서 더 복잡한 작업들을 해보겠어요!

✅ 학습 완료 체크리스트

이번 시간에 배운 내용들을 모두 이해했는지 확인해보세요!

학습 내용 이해했나요?
fetch의 기본 개념
기본 사용법과 문법
주요 특징과 차이점
자주 하는 실수들
실전 예제 이해

🎯 추가 연습 문제들

조금 더 연습하고 싶은 친구들을 위한 추가 문제들입니다!

추가 문제 1. 간단한 데이터를 가져와서 콘솔에 출력하는 fetch 함수를 만들어보세요.

// 답:
async function fetchSimpleData() {
    try {
        let response = await simulateFetch('https://api.example.com/simple');

        if (response.ok) {
            let data = await response.json();
            console.log("데이터:", data);
            return data;
        } else {
            console.log("요청 실패:", response.status);
        }
    } catch (error) {
        console.log("에러:", error);
    }
}

fetchSimpleData();

추가 문제 2. 사용자 정보를 가져와서 이름과 취미만 출력하는 함수를 만들어보세요.

// 답:
async function getUserBasicInfo() {
    try {
        let response = await simulateFetch('https://api.example.com/users/1');
        let user = await response.json();

        console.log("이름:", user.name);
        console.log("취미:", user.hobby);

        return user;
    } catch (error) {
        console.log("사용자 정보를 가져올 수 없습니다:", error);
        return null;
    }
}

getUserBasicInfo();

추가 문제 3. 날씨 정보를 가져와서 온도만 출력하는 함수를 만들어보세요.

// 답:
async function getTemperature() {
    try {
        let response = await simulateFetch('https://api.weather.com/current');
        let weather = await response.json();

        console.log("현재 온도:", weather.temperature + "도");

        return weather.temperature;
    } catch (error) {
        console.log("날씨 정보를 가져올 수 없습니다:", error);
        return null;
    }
}

getTemperature();

추가 문제 4. fetch가 반환하는 것은 무엇이고, 실제 데이터를 얻으려면 어떻게 해야 하나요?

: fetch는 Promise를 반환하며, 이 Promise는 Response 객체로 resolved됩니다. 실제 데이터를 얻으려면 response.json()이나 response.text() 메서드를 사용해야 합니다.

추가 문제 5. 다음 코드에서 문제점을 찾고 수정해보세요.

async function getData() {
    let response = await simulateFetch(url);
    let data = response.json();
    console.log(data);
}

: response.json()에 await가 없어서 Promise 객체가 출력됩니다. 수정된 코드:

async function getData() {
    let response = await simulateFetch(url);
    let data = await response.json();
    console.log(data);
}

🔄 단계별 진행 과정 정리

지금까지 배운 내용을 단계별로 다시 한번 정리해볼게요.

1단계 과정: 요청 → 응답 확인 → 데이터 변환 → 결과 출력

2단계 과정: 사용자 정보 요청 → 날씨 정보 요청 → 정보 조합 → 추천 메시지

3단계 과정: 시도 → 실패 시 재시도 → 최종 성공/실패 처리

📂 마무리 정보

오늘 배운 13.5.1 내용이 여러분의 자바스크립트 지식에 잘 저장되었나요? 다음 시간에는 더 재미있는 내용으로 만나요!

기억할 점: 오늘 배운 내용을 꼭 연습해보시고, 궁금한 점이 있으면 언제든 다시 돌아와서 읽어보세요.


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