JavaScript

숙제6 - async/await 로 리팩토링 하기

차돌박이츄베릅 2023. 5. 29. 01:25

문제

이번 주차의 문제는 아래의 코드를 async/await 로 리팩토링 하기 입니다.

class HttpError extends Error {
    constructor(response) {
      super(`${response.status} for ${response.url}`);
      this.name = 'HttpError';
      this.response = response;
    }
  }
 
 
  function loadJson(url) {
    return fetch(url)
      .then(response => {
        if (response.status == 200) {
          return response.json();
        } else {
          throw new HttpError(response);
        }
      })
  }
 
  function narutoIsNotOtaku() {
    let title = prompt("애니메이션 제목을 입력하세요.", "naruto");
 
      return loadJson(`https://animechan.vercel.app/api/random/anime?title=${title}`)
      .then(res => {
              alert(`${res.character}: ${res.quote}.`);
        return res;
      })
      .catch(err => {
        if (err instanceof HttpError && err.response.status == 404) {
          alert("일치하는 애니메이션이 없습니다. 일반인이시면 naruto, onepiece 정도나 입력해주세요!");
          return narutoIsNotOtaku();
        } else {
          throw err;
        }
      });
  }
 
  narutoIsNotOtaku();

 


내가 작성한 코드

이건 뭐 감도 안와..

왜 원본 코드고 정답 코드고 오류 뜨는 것일까

class HttpError extends Error {
    constructor(response) {
      super(`${response.status} for ${response.url}`);
      this.name = 'HttpError';
      this.response = response;
    }
  }
 
 
  function loadJson(url) {
    return new Promise(function (resolve) {
        return fetch(url)
        .then(response => {
            if (response.status == 200) {
            return resolve(response.json());
            } else {
            throw new HttpError(response);
            }
        })
    });
  }
 
  async function narutoIsNotOtaku() {
    let title = prompt("애니메이션 제목을 입력하세요.", "naruto");

    let _loadJson = await loadJson(`https://animechan.vercel.app/api/random/anime?title=${title}`);
 
      return _loadJson
      .then(res => {
              alert(`${res.character}: ${res.quote}.`);
        return res;
      })
      .catch(err => {
        if (err instanceof HttpError && err.response.status == 404) {
          alert("일치하는 애니메이션이 없습니다. 일반인이시면 naruto, onepiece 정도나 입력해주세요!");
          return narutoIsNotOtaku();
        } else {
          throw err;
        }
      });
  }
 
  narutoIsNotOtaku();

 

정답

// 브라우저에서 구동하기
// prompt()와 같은 브라우저에서만 동작하는 api가 있기 때문에 브라우저에서 테스트 함
// js 파일 연결한 html 파일에서 VSCode Live Server를 통해 확인

// 비동기 then catch부분을 async, await로 바꿔줄 예정

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

// 이 함수를 리팩토링 할 것이므로, function 앞에 async 키워드를 입력해서 해당 함수가 비동기적으로 동작한다는 것을 알려줘야 함. 비동기 로직이 들어가는 부분 앞에는 await 키워드를 붙여줘야 함
// 비동기 결과 값을 then을 이용했을 땐 콜백함수 인자 response로 받고 있는데,
// 우리는 별도로 선언해주겠음

async function loadJson(url) {
    // url로 fetch요청(비동기 통신을 할 때 해당 서버로 요청을 보내기 위한 수단)을 하고
    const response = await fetch(url);
    // async 블록 안에서 await 키워드를 만나면 이부분이 끝날 때 까지 아래쪽으로 내려가지 않고 기다림

    // 보통 성공했을 때 200 이라고 함
    if (response.status == 200) {
        return response.json();
    } else {
        throw new HttpError(response);
    }
    // 동일하게 분기를 하되
    // 위에서 통신을 요청하는 부분만 await로 막아둔거

    // return fetch(url).then((response) => {
    //     if (response.status == 200) {
    //         return response.json();
    //     } else {
    //         throw new HttpError(response);
    //     }
    // });
}

// function 키워드 앞에 async 키워드를 붙여줌으로써 해당 블록이 비동기 관련된 로직이 들어갈 수 있다라고 명시해줌
// 비동기 로직이 필요한 부분에 await 키워드를 입력해서 해당 부분 밑으로는 내려가지 못하도록 막는 것. 기다리게 하는 것
async function narutoIsNotOtaku() {
    // 사용자의 입력이 진입이 될 때까지 계속 기다려야만 함 -> while문으로 구현할 거
    // 1. 어떤 조건이 충족될 때까지 안을 영원히 돌도록
    // 2. 조건은 사용자의 입력이 들어왔을 때-는 비동기 통신에 요청을 하고 바로 break문을 통해서 빠져나가도록 할 것
    let title;
    let res;
    while (true) {
        title = prompt('애니메이션 제목을 입력하세요.', 'naruto');

        // 비동기 통신 요청 - 성공, 실패할 수 있음 -try catch문으로 맞출 거
        try {
            // loadJson부분을 try해서 결과값을 res에 담음
            // 근데 loadJson부분은 비동기 로직이기 때문에 await 키워드를 이용해서 밑으로 바로바로 흐르지 않고 이 로직을 끝날 때까지 기다리게끔 막아줬음
            res = loadJson(`https://animechan.vercel.app/api/random/anime?title=${title}`);
            // 이 res(response)를 받아온 다음엔 break키워드를 통해서 while문을 빠져나간 후에 우리가 필요한 alert를 찍어줌
            break;
        } catch (err) {
            if (err instanceof HttpError && err.response.status == 404) {
                alert('일치하는 애니메이션이 없습니다. 일반인이시면 naruto, onepiece 정도나 입력해주세요!');
                // return narutoIsNotOtaku(); // 다시 입력받는 부분을 while문에 넣어줘서 이 부분은 필요없게 됨
            } else {
                throw err;
            }
        }
    }

    alert(`${res.character}: ${res.quote}.`);
    return res;

    // let title = prompt('애니메이션 제목을 입력하세요.', 'naruto');

    //     .then((res) => {
    //         alert(`${res.character}: ${res.quote}.`);
    //         return res;
    //     })
    //     .catch((err) => {
    //         if (err instanceof HttpError && err.response.status == 404) {
    //             alert('일치하는 애니메이션이 없습니다. 일반인이시면 naruto, onepiece 정도나 입력해주세요!');
    //             return narutoIsNotOtaku();
    //         } else {
    //             throw err;
    //         }
    //     });
}

narutoIsNotOtaku();