개발기록장

[JavaScript] 콜백함수와 콜백 지옥 탈출을 위한 promise, async/await (3) 본문

TIL/JavaScript

[JavaScript] 콜백함수와 콜백 지옥 탈출을 위한 promise, async/await (3)

yangahh 2020. 12. 30. 06:18

 

 

 

2020/12/30 - [TIL/JavaScript] - [JavaScript] 콜백함수와 콜백 지옥 탈출을 위한 promise, async/await (2)

 

[JavaScript] 콜백함수와 콜백 지옥 탈출을 위한 promise, async/await (2)

이전 글 2020/12/30 - [TIL/JavaScript] - [JavaScript] 콜백함수와 콜백 지옥 탈출을 위한 promise, async (1) [JavaScript] 콜백함수와 콜백 지옥 탈출을 위한 promise, async (1) 콜백함수란? 자바스크립트에서..

devvvyang.tistory.com

 

async 와  await

 

async 와 await는 promise를 좀 더 간결하고 간편하고 동기적으로 실행되는 것처럼 보이게 만들어 준다.

async 와 await는 새로운 것이 아니라 promise 위에 쓰는 api를 제공하는 것이다.

 

** 이런걸 syntacic sugar라고 한다. class도 syntacic sugar

 

 

 

 

1. async 사용 예시

 

// promise를 사용한 경우
function fetchUser() {
  // 사용자 데이터를 백앤드에서 받아오는 함수(네트워크와 통신하는데 10초 걸린다고 가정)
  
    
  return new Promise((resolve, reject) => { // 이 함수가 promise라는 오브젝트를 가지고 있으면 then이라는 콜백함수를 호출할때 user데이터를 불러줄게(=약속!)
    // 10초 걸리는 작업 코드...(가정)
    // return "John"; // 이렇게 resolve, reject 둘다 호출하지 않으면 계속 pending상태가 된다.
    // 따라서 promise안에 resolve나 reject를 이용해서 완료해줘야 한다.
    resolve("John");
  });
}


let user = fetchUser();
user.then(console.log);


// promise를 사용한 코드에서 함수 정의부분 앞에 async를 붙이고 함수 내부에 promise부분 코드를 지우면 끝!
// async를 쓰면 코드블럭이 자동으로 promise로 바뀌는 원리.
async function asyncFetchUser() {
  return "Kim";
}


let user2 = asyncFetchUser();
user2.then(console.log);


 

 

 

2. await 사용 예시

 

// await 키워드는 async가 붙은 function 내부에서만 사용가능.

function delay(ms) {
  /*
  return new Promise((resolve) => {
    // 정해진 ms시간이 지나면 resolve 호출.
    setTimeout(resolve, ms); // (a)=> {function_name(a)}는  function_name 으로 생략가능
  });
  */
  
  // 위에꺼 한줄로 쓰면
  return new Promise((resolve) => setTimeout(resolve, ms));
}


async function getApple() {
  await delay(3000); // delay함수가 실행될때까지 아래 코드를 실행하지 않고 기다림.
  // 원래대로라면 delay는 비동기처리이기 때문에 delay함수를 실행시키고 바로 아래 코드인 return이 실행된다.
  return "🍎";
}

async function getBanana() {
  await delay(3000);
  return "🍌";
}





// await를 쓰지 않고 promise로 쓴다면?
function getBanana() {
    return delay(3000).then(()=>"🍌");
}

 

 

 

3. await를 이용한 병렬처리 예시

 


// 사과와 바나나를 한 번에 다 따는 함수
function pickFruits() {
  return getApple().then((apple) => {
    return getBanana().then((banana) => `${apple} + ${banana}`);
  });
}

pickFruits().then((result) => console.log(result)); // 6초 뒤에 결과가 나옴. (getApple 리턴받는데 3초, getBanana 리턴받는데 3초)




// >> pickFruits와 같이 promise도 중첩으로 주면 가독성이 떨어짐. >> async 사용 권장
async function pickFruits2() {
  const apple = await getApple();
  const banana = await getBanana();

  return `${apple} + ${banana}`;
}

pickFruits2().then((result) => console.log(result)); // 똑같이 6초 뒤에 결과가 나옴.




// await 병렬 처리
async function pickFruits3() {
  const applePromise = getApple(); // promise는 오브젝트를 만들자마자 안에 있는 코드블럭이 바로 실행됨.(getApple안에있는 코드들이 바로 실행된다는 의미.)
  const bananaPromise = getBanana();

  const apple = await applePromise;
  const banana = await bananaPromise;

  return `병렬 처리 ${apple} + ${banana}`;
}

pickFruits3().then(console.log); // getApple()과 getBanana()를 동시에 수행하기 때문에 3초 걸림




// promise에서 제공하는 API를 이용하여 병렬처리하기
function pickAllFruits() {
  //promise들을 배열 형태로 전달하면 모든 promise들이 병렬적으로 처리되서 값을 다 받을때까지 모아준다.
  return Promise.all([getApple(), getBanana()]) 
    .then((fruits) => fruits.join(" + "));
}

pickAllFruits().then((result) => console.log(result));




// 가장 먼저 수행된 것만 받기
function pickOnlyOne() {
  return Promise.race([getApple(), getBanana()]).then((fruit) => fruit);
}

pickOnlyOne().then(console.log);

 

 

 


 

 

콜백 지옥을 async & await로 해결하는 방법

** 이전 글 참고

// Callback Hell 예제 >> promise >> async & await로 해결하는 방법


class UserStorage {
  async loginUser(id, password) {
    if (
      (id === "user1" && password === "pwpw1") ||
      (id === "user2" && password === "pwpw2")
    ) {
      resolve(id);
    } else {
      reject(new Error("not found"));
    }
  }

  async getRoles(user) {
    if (user === "user1") {
      resolve({ name: "user1", role: "admin" });
    } else {
      reject(new Error("no access"));
    }
  }
}


// 구현할 프로세스
// 1. 사용자에게 id, password 입력받기
// 2. 로그인
// 3. 로그인 성공 시 받아온 id로 role 받아오기
// 4. 성공적으로 role을 받아오면 name과 role 출력


let id = prompt("id를 입력해주세요.");
let password = prompt("password를 입력해주세요.");

let userStorage = new UserStorage();

userStorage
  .loginUser(id, password)
  .then(userStorage.getRoles)
  .then((userWithRole) =>
    alert(`Hello ${userWithRole.name}! you have a ${userWithRole.role} role.`)
  )
  .catch(alert);