프로그래머스 데브코스 38일차(promise,async-await)

박상하·2023년 12월 21일
0

트러블 슈팅 ☄️

수업에서 API를 설계하며 만들어가는 실습을 스스로 해보는 과정을 겪고있다.
수업에서는 프론트단이 있다고 가정하고 Postman 프로그램을 이용해서 API를 호출해보지만
스스로 프론트단을 만들어보고 만들어진 프론트에서 요청을 보내보는 연습중이다.

cors, headers등 덕분에 다양한 상황을 마주하게 돼서 공부가 더 되는거 같다.

이번에 겪은 트러블 슈팅은 비동기처리를 하며 생긴 상황이다

vanilla javascript로 Front-end는 SPA방식으로 렌더링되는 것처럼 보이도록 history 내장 메서드를 사용하여
URL의 주소를 변경하고 routes가 이 URL의 주소를 받아서 원하는 컴포넌트를 Rendering 하도록 설계하였다.
Back-end도 역시 라우터를 사용하여 해당 URL의 주소를 받아 route를 통해 원하는 API를 보내줄 수 있도록 하였다.

그런데 문제는 Mypage.js에서 발생하였다.

그러니깐 my page.js의 주소인

이처럼 "/mypage로 요청이 들어오면

위 처럼 innerHTML을 수정하는 방식을 택했는데

처음 mypage.js를 보면 fetch로 WAS에 GET요청을 보내 원하는 채널 DB를 가져오고자한다.

그런데 보기와 같이 getDB를 Mypage()로 실행을 하면 화면에는
Promise Object가 반환되어 화면에 보여졌다..

지금은 학습을 하여 다시 이해를 했지만 이번 기회에 Promise와 async await를 다시 복기
해볼 수 있었다.
이전에는 제대로 이해하지 못했었군..

원하는 화면은 이게 뿌려져야했다.

문제 Async로 함수를 선언했는데 Await를 하지 않았다 🎯

Promise ✨

자 먼저 Async전에 Promise를 알아야한다.

Promise는 비동기를 다룰 수 있는 수단은 맞다.

Promise는 진행 상태를 나타내는 객체로 진행상태과 값을 가지고 있다.

Promise 객체를 Return하도록 만드는 함수는 다음과 같다.

function test(){
 return new Promise((resolve,reject)=>{
  //이곳에 비동기 함수를 작성하고 변수로 만약 저장했다면?
   resolve(저장된변수 또는 어떤 값)   
 }) 
  
}

이렇게 하면 test는 ?? 저장된 변수 또는 어떤 값을 프로미스 객체로 return을한다.

즉 프로미스 객체를 리턴하는데 진행상황과 값을 가지고 있는 프로미스 객체를 리턴한다. 그 값을 그럼 어떻게 가져올 수 있나?

test.then((여기에담김)=>여기서 뭐 console.log(여기에담김))
//이런식으로 비동기적인 값을 받아올 수 있다.

이처럼 만약 비동기적인 함수가 성공을 하면 프로미스 객체에 성공상태와 해당 값이 담기는데
성공했을 때는 then에 실패했을 때는 catch에 담긴다.

객체이기 때문에 .으로 접근한다.

즉 Promise라는 객체를 통해 비동기적인 함수의 상황을 알 수 있고 그 담겨오는 값을 사용해 연이어 무언가를 해줄 수 있다.

그런데 Promise객체를 return하는 함수를 만들 때 더 간단한 방법이 있다.

Async ✨

Async를 함수앞에 붙여주면 자동으로 어떤 값이든 Promise객체에 담아 return해준다.

예를들어 다음과 같은 코드가 있다고 가정해보자

function test(){
 return new Promise((resolve,reject)=>{
   //어떤 비동기적인 함수
  resolve("Hello") 
 }) 
}

위 코드는 비동기적인 함수가 성공을 하면 Hello라는 값을 프로미스 객체에 담아온다.
즉, then이라는 메서드에 담겨진다.

그런데 이것보다 더 간단하게 Promise객체를 리턴하는 함수를 만들 수 있다.

바로 Async이다!

async function test(){
 return "Hello" 
  
}

위 코드와 동일한 리턴을 건낸다.

즉 Async는 무조건 프로미스 객체를 리턴한다.
정확히는 진행상황과 그 값을 리턴한다.
만약 성공했다면 원하는 값이 담길 것이고 실패했다면 에러가 담길것이다.

이렇게 정리할 수 있다.

Async는 Promise객체를 리턴하게 만들어준다.

그럼 다음과 같이 사용이 가능할 것이다. test.then((res)=>alert(res))

그런데 이렇게 then이 계속해서 연결되는 부분은 꽤 보기 불편할 수 있다. 좀 더 멋스럽게 바꿔보자

멋 스 럽 게

await ✨

이런 프로미스 객체를 잘 기다려주는 녀석이 await이다.

프로미스 객체는 진행상황에 대한 정보를 저장한다. Pending, fulfill등

그럼 프로미스가 비동기적인 작업을 마칠때까지 기다려준다.

Javascript엔진이 위에서 아래로 코드를 읽을 때 Await를 만나면 잠시 기다려주고 다음 아래로 순차적으로 읽어나간다.

그럼이제 then을 쓰지 않아도 then다.

async function test(){
  //비동기적뭐시기를하겠죠
 return "Hello" 
  
}

async function go(){
  const mention = await test()
  console.log(mention)
}
go()
// hello출력

이렇게 되는 것이다.

await는 프로미스객체를 기다려준다.

라고 정리할 수 있다.

async는 프로미스 객체를 리턴하도록해준다.
await는 프로미스 객체를 기다려준다.

환상의 짝궁이다.

그렇기 때문에 await는 async안에서 사용이 가능한 특징이 있다.

오류 분석 📈

그럼 아까 필자가 작성한 코드를 살펴보면 이제 이해가 된다.


export async function Mypage() {
  //db를 받아오기
  //get으로 받아와야할듯
  let channelDB = await getDB();
  
  return `<div>
  <h1>U TUBE</h1>
  <h3>~~님의 계정</h3>
  <h3>채널 리스트</h3>

  <button id="Make_Channel">채널관리</button>
  <button id="Update_Channel">채널수정</button>
  </div>`;

}

async function getDB() {
  const data = await fetch("http://localhost:1234/db", {
    method: "GET",
  });
  const { channelDB } = await data.json();
  return channelDB;
}
//여기까지는 문제가 없다 channelDB는 await를 통해 잘 담아진다.
  1. getDB는 async가 붙어있기 때문에 promise객체를 반환할 것이다.
  2. 그리고 Fetch는 promise객체를 반환하기 때문에 await로 기다려준다.
  3. 그리고 받아온 data를 json처리를 해주며 channelDB에 저장할 수 있도록한다.
  4. 그리고 return이된다.
  5. async로 선언된 Mypage함수는 Promise객체를 리턴할 것이다.
  6. channelDB를 Await해서 받아왔고 그 다음 return이 될 것이다.

여기까지는 문제가 없다 그럼 사용하는 부분에서 살펴보자

export const changeUrl = (requestUrl) => {
  history.pushState(null, null, requestUrl);
  root.innerHTML = routes[requestUrl]();
};

이 함수를 통해 Router되어 해당 Root의 innerHTML이 다시 그려진다.

그럼데 해당 changeUrl은 프로미스 객체를 반환하지 않는 일반 함수이다.
그럼 routerequestUrl은 결국 Mypage를 호출 할것이다.

그런데 Mypage는? Promise객체를 반환한다.

그래서 InnerHTML에 Promise객체가 반환이 되는 것이다. 그래서 화면에 Promise Object가 나와있었다.

오류 해결 🌞

Promise Object가 나온 이유는 해당 Promise객체를 기다려주지 않아서 이다. 결국 Promise객체는
기다려줘야한다. 아니면 해당 값을 가져온 시점 즉, 진행상황이 완료된 후에 다음 처리를 해주어야한다.

그래서 이렇게 수정할 수 있다.

export const changeUrl = async (requestUrl) => {
  history.pushState(null, null, requestUrl);
  root.innerHTML = await routes[requestUrl]();
};

이렇게 changeUrl도 Promise객체를 리턴하는 함수로 만든다. 사실 await를 쓰기 위해 저렇게 선언을 해준것이다. await를 통해 기다렸다가 원하는 값을 가져와 root.innerHTML에 넣어 줄 수 있도록한다.

해당 changeUrl은 Return값이 필요가 없기 때문에 이렇게 사용할 수 있다.

정리 📚

Promise는 진행상황과 값을 저장하는 객체
Async는 함수앞에 붙어 Promise를 Return하는 함수로 만들어준다.
Await는 Promise함수가 완료되길 기다려 그 값을 받아온다.

그리고 Promise상태가 성공적으로 완료되면 then메서드의 메개변수로 그 값이들어간다.
Promise.then(성공값)
만약 실패했다면 catch메서드의 매개변수로 에러가 들어간다.
Promise.catch(에러값)

0개의 댓글

관련 채용 정보