본문으로 바로가기

4주차 강의를 모두 듣고 과제를 진행했는데 Promise 기반으로 구현된 fetch 통신 코드를 async/await 기반으로 리팩토링하는 것이었습니다. async/awit 기반에 try-catch로의 리팩토링은 무난히 끝났지만...

그런데 이게 무슨 일이야,,,?

then-catch러 구현하려고 할 때 예상치 못한 에러가 발생했습니다.

 

일단 try-catch로 리팩토링한 코드부터 보시죠

 

1. try-catch

class HttpError extends Error {
            constructor(response) {
                super(`${response.status} for ${response.url}`);
                this.name = 'HttpError';
                this.response = response;
            }
        }

 

단순히 에러를 던져주는 커스텀 클래스입니다. 이 부분은 고정 변하지 않습니다.

async function loadJson(url) {
            let res = await fetch(url);
            if (res.status == 200) {
                return res.json();
            } else {
                throw new HttpError(res);
            }
        }

 

fetch 요청을 비동기적으로 처리하고, await을 사용하여 응답을 기다립니다.

응답 코드가 200일 경우 응답 데이터를 json 형식으로 변환하여 return 해줍니다.

에러가 발생할 경우 HttpError를 던집니다.

async function koreanMovie() {
            try {
                let res = await loadJson(`https://klassic-quote-api.mooo.com/v1/random-quot`);
                console.log(res);
                console.log(`${res.author}: ${res.quote}`);
                alert(`${res.author}: ${res.quote}`);
            } catch (err) {
                if (err instanceof HttpError && err.response.status == 404) {
                    console.log(err);
                    alert("무언가 에러가 발생했군요!");
                    return koreanMovie();
                } else {
                    alert("알 수 없는 에러:", err);
                    throw err; 
                }
            }
        }

 

loadJson 함수에서 응답을 무사히 받으면 값을 출력해주고

에러가 발생하면 재귀 호출로 koreanMovie를 다시 실행시켜주도록 구현했습니다.

 

이제 then-catch 형식으로 리팩토링 했을 때 입니다....

2. then-catch

async function loadJson(url) {
            await fetch(url).then((res) => {
                if (res.status == 200) {
                    return res.json(); 
                } else {
                    throw new HttpError(res);
                }
            });
        }

 

await을 통해 Promise가 반환될 때까지 기다리고 성공적으로 반환되면 json 형식으로 변환하여 반환합니다. 

async function koreanMovie() {
            await loadJson(`https://klassic-quote-api.mooo.com/v1/random-quote`).then((res) => {
                console.log(res);
                console.log(`${res.author}: ${res.quote}`);
                alert(`${res.author}: ${res.quote}`);
            }).catch((err) => {
                console.error(err);
                alert(err);
            }
            )
        }

 

여기서 문제가 발생했습니다.

?????

왜 author를 읽지 못해...

혹시 몰라서 console을 추가해봤지만 돌아오는 것은 undefined 뿐...

 

이제 마지막으로 네트워크 창에 들어가서 데이터 응답이 잘 됐나 확인 해봤는데

??????

 

 

넌 또 왜 들어있니....?

 

그렇다면 문제는

async function loadJson(url) {
            await fetch(url).then((res) => {
                if (res.status == 200) {
                    return res.json(); 
                } else {
                    throw new HttpError(res);
                }
            });
        }

 

이 쪽에서 반환을 못했기 때문

 

return res.json() 이 있지 않냐고요? 

네, 저도 그럴 줄 알았습니다.

 

그 return 값은 콜백 함수의 값으로 then 내에서만 영향을 미칠 뿐 외부 스코프까지 영향을 못 미치기 때문입니다... 따라서 await 앞에 return을 작성하여 then 메서드의 결과값이 상위 컨텍스트까지 전달할 수 있도록 만들어야 합니다.

async function loadJson(url) {
            return await fetch(url).then((res) => {
                if (res.status == 200) {
                    return res.json(); 
                } else {
                    throw new HttpError(res);
                }
            });
        }

 

이렇게 하면 loadJson 함수를 실행시킬 시 res.json()이 반환값이 됩니다. 

 

실행 컨텍스트 공부하러 가야겠습니다.....✨