프론트엔드/비동기

async / await

테오구 2021. 8. 28. 16:50
728x90

async & await

  • 프로미스 체이닝을 계속 하다보면 코드의 가독성이 떨어짐
  • async 와 await는 Promise를 간결/간편하고 동기적으로 실행되는것 처럼 보이게 만들어주는 API
  • async 와 await는 새로운 것이 추가 된게 아니라, 기존에 존재하는 Promise 위에 조금 더 간편한 API를 제공함 이런 것을 syntactic sugar 라고 한다 (Class도 마찬가지..)
  • 비동기 처리를 반드시 해야하는 이유

    • JS 엔진은 블록({})안에 코드를 동기적으로 실행(처리) 함
    • 시간이 오래 걸리는 코드를 비동기 처리를 전혀 하지 않으면, 다음 코드에 문제가 발생할 수 있음
    • 예를 들어 서버에서 data를 받아와서 웹페이지에 출력하는 시나리오가 있다
    • data를 받아 오는데 10초가 걸림, 근데 비동기 처리를 안하면 텅 빈 data를 출력 해버림
    • Promise 상황극: 내가 언제 유저의 data를 받아 올진 모르겠지만 내가 약속할께, Promise라는 object를 가지고 있으면, 여기에 니가 then 이라는 콜백함수만 등록해 놓으면, 유저의 data가 준비 되는대로 니가 등록한 콜백함수를 불러줄께

1. async

  • 1.1 기존 방식(Promise)
// 프로미스를 사용하면 반드시 resolve와 reject를 호출해야 함
function fetchUser() {
  return new Promise((resolve, reject) => {
    // return `ellie`; // 프로미스 pending 상태
		resolve(`ellie`); // 프로미스 fulfilled 상태
		// reject(new Error(`error`)); // 프로미스 rejected 상태
  });
}

const user = fetchUser();
// console.log(user);
user.then(user => console.log(user));

1.2 async 사용

  • async를 사용하면 함수의 코드 블록이 자동으로 Promise로 변환이 되어짐 (대박!)
// 1. 함수 선언식
async function fetchUser() {
  return `ellie`;
}

// 2. 함수 표현식
const fetchUser = async function() {
  return `ellie`;
};

// 3. 화살표 함수
const fetchUser = async () => {
  return `ellie`;
};

// fetchUser().then(data => console.log(data)); // 함수로 바로 호출
const user = fetchUser(); // 변수에 할당해서 호출
user.then(data => console.log(data));
console.log(user);

2. await

2.1 기존 방식(Promise)

  • 콜백 지옥이 떠오름..
function delay(ms) {
  return new Promise (resolve => setTimeout(resolve, ms));
}

function getApple() {
  return delay(1000)
  .then(() => `🍎`);
}
function getBanana() {
  return delay(1000)
  .then(() => `🍌`);
}

function pickFruits() {
  return getApple()
  .then(apple => {
    return getBanana().then(banana => `${apple} + ${banana}`);
  });
}
pickFruits().then(result => console.log(result));

2.2 await 사용 (error 처리: try/catch문)

  • await는 async 함수 내부에만 사용 가능
  • getApple과 getBanana는 서로 독립적인 코드인데 순차적으로 실행됨 → 비효율
function delay(ms) {
  return new Promise (resolve => setTimeout(resolve, ms));
}

async function getApple() {
  await delay(1000);
  // throw new Error(`error: apple`); // error 발생
  return `🍎`;
}
async function getBanana() {
  await delay(1000);
  // throw new Error(`error: banana`);
  return `🍌`;
}

async function pickFruits() {
  let apple = null;
  try {
    apple = await getApple();
  } catch(error) {
    console.log(error);
  }
  let banana = null;
  try {
    banana = await getBanana();
  } catch(error) {
    console.log(error);
  }
  return `${apple} + ${banana}`;
}
pickFruits().then(result => console.log(result));

2.3 await 병렬 처리

function delay(ms) {
  return new Promise (resolve => setTimeout(resolve, ms));
}

async function getApple() {
  await delay(1000);
  return `🍎`;
}
async function getBanana() {
  await delay(1000);
  return `🍌`;
}

// 방법 1: 무식한 코드
async function pickFruits() {
  // 프로미스 객체는 선언 즉시 바로 실행됨
  // getApple과 getBanana는 병렬(독립적)로 실행됨
  const applePromise = getApple();
  const bananaPromise = getBanana();
  // 동기화
  const apple = await applePromise; 
  const banana = await bananaPromise;
  return `${apple} + ${banana}`;
}
pickFruits().then(result => console.log(result));

// 방법 2: Promise APIs 사용
function pickAllFruits() {
  return Promise.all([getApple(), getBanana()]).then(fruits => {
    return fruits.join(` + `);
  });
	// return Promise.all([getApple(), getBanana()]);
}
pickAllFruits().then(console.log);


// 번외: 비동기 처리중 먼저 리턴하는 녀석만 출력
function pickOnlyOne() {
  return Promise.race([getApple(), getBanana()]);
}
pickOnlyOne().then(console.log);

 

728x90

'프론트엔드 > 비동기' 카테고리의 다른 글

fs.readFile  (0) 2021.10.19
fetch를 이용한 네트워크 요청  (0) 2021.10.15
node.js  (0) 2021.10.15
비동기 호출  (0) 2021.10.14
비동기  (0) 2021.10.14