[TIL] Promise와 async / await

danbii·2020년 5월 7일
0

TIL

목록 보기
13/20

동기와 비동기

동기적(Synchronous) 처리

  • 이전의 작업이 끝날 때 까지 다음 작업을 할 수 없다. 이전의 작업이 끝나야 다음 작업이 실행되는 것.

비동기적(Asynchronous) 처리

  • 코드를 실행할 때 흐름이 멈추지 않는다. 동시에 여러가지 작업을 처리할 수 있고, 기다리는 중에 다른 함수를 호출할 수도 있다.

Promise

  • 비동기 작업을 조금 더 편하게 작업할 수 있도록 ES6에 도입된 기능.
  • 이전에 비동기 작업을 처리할 때(어떤 작업이 끝나고 나서 다른 작업을 해야 할 때) 콜백 함수로 처리를 해줘야 했다.
  • 비동기 작업이 많아지면 콜백 함수로 처리하는 게 복잡해지기 때문에 Promise를 사용하게 되었다.

Promise 만드는 방법

  • Promise는 성공할 수도 있고, 실패할 수도 있다.
  • 성공할 때는 resolve를 호출하고 실패하면 reject를 호출 한다.
// 성공할 때 
const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => { // 비동기적 코드를 만들기 위해
    resolve('result'); // 결과 반환
  }, 1000)
});

// Promise가 끝난 뒤 할 작업 설정
myPromise.then(result => {
  cnosole.log(result);
})
// 결과: result
// 실패할 때
const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(new Error());
  }, 1000)
});

myPromise.then(result => {
  console.log(result);
}).catch(e => {
  console.error(e);
})
// 결과: Error at <anonymous>:3:12 

Promise 사용

  • n 값이 5가 되면 에러가 발생
function increaseAndPrint(n) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const value = n + 1;
      if (value ===  5) {
        const error = new Error();
        error.name = 'ValueIsFiveError'; // 에러 이름 정함
        reject(error);
        return;
      }
      console.log(value);
      resolve(value); // 결과 반환
    }, 1000);
  })
}

increaseAndPrint(0).then(n => {
  console.log('result: ', n);
})
increaseAndPrint(0).then(n => {
  return increaseAndPrint(n);
}).then(n => {
  return increaseAndPrint(n);
}).then(n => {
  return increaseAndPrint(n);
}).then(n => {
  return increaseAndPrint(n);
}).then(n => {
  return increaseAndPrint(n);
}).catch(e => {
  console.error(e);
})
  • 아래와 같이 나타낼 수도 있다.
increaseAndPrint(0).then(increaseAndPrint)
  .then(increaseAndPrint)
  .then(increaseAndPrint)
  .then(increaseAndPrint)
  .then(increaseAndPrint)
  .catch(e => {
  console.error(e);
})
  • promise를 사용하면 비동기 작업이 많아져도 코드가 많이 복잡해 지지 않는다.
  • 하지만 어떤 부분에서 에러가 발생하는지 알기 어렵고, then으로 되어 있기 때문에 특정 조건에서 하는 작업을 나타내기 어렵다.

async / await

  • promise를 더 쉽게 사용할 수 있도록 해주는 ES8 문법
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function process() {
  console.log('안녕하세요!');
  await sleep(1000); // promis 앞 부분에 await
  console.log('반갑습니다!');
}

process();
  • 결과: '안녕하세요!' -> 1초 뒤 -> '반갑습니다!'
    async를 사용하면 함수의 결과는 promise를 반환한다.
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function process() {
  console.log('안녕하세요!');
  await sleep(1000);
  console.log('반갑습니다!');
  return true;
}

process().then(value => {
  console.log(value);
});
  • 결과: '안녕하세요!' -> 1초 뒤 -> '반갑습니다!' -> true
    다른 값을 return 하고 싶을 때는 .then을 이용한다.

async / await 에러 발생

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

async function makeError() {
  await sleep(1000);
  const error = new Error();
  throw error; // 에러 발생 시킬 때
}

async function process() {
  try {
    await makeError();
  } catch (e) { // e는 위의 error 객체
    console.error(e);
  }
}
process();
  • 1초 뒤에 에러가 발생한다. 에러를 잡을 때 try - catch문 사용

화살표 함수에서 async 사용

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

const getDog = async () => {
  await sleep(1000);
  return '멍멍이';
}

const getRabbit = async () => {
  await sleep(500);
  return '토끼';
}

const getTurtle = async () => {
  await sleep(3000);
  return '거북이';
}

async function process() {
  const dog = await getDog();
  console.log(dog);
  const rabbit = await getRabbit();
  console.log(rabbit);
  const turtle = await getTurtle();
  console.log(turtle);
}

process();
  • 위 처럼 실행 되면 getDog()가 실행 되고 끝난 뒤 -> getRabbit()가 실행 되고 끝난 뒤 -> getTurtle()이 실행 된다. (동기적 처리 방식 처럼 실행 됨)

Promise.all()

async function process() {
  try {
     const results = await Promise.all([getDog(), getRabbit(), getTurtle()]);  
console.log(results);
  } catch (e) {
    console.log(e);
  }  
}
  • 여러 개의 Promise를 동시에 실행 시키려면, 배열에 promise를 등록 하고, Promise.all()로 감싸준다.
  • 모든 Promise가 한꺼번에 시작 하고 가장 늦게 끝난 Promise가 3초가 걸리므로, 그 Promise가 끝난 뒤 [ '멍멍이', '토끼', '거북이' ]를 결과로 볼 수 있다.

    📌 Promise.all() 안에 있는 Promise 중 하나라도 에러가 발생하면 전부 다 에러로 간주하고, catch 안의 에러 메세지를 띄운다.

async function process() {
 const [dog, rabbit, turtle] = await Promise.all([getDog(), getRabbit(), getTurtle()]);
  console.log(dog);
  console.log(rabbit);
  console.log(turtle);
}
  • 비구조화 할당을 이용하여 각 Promise의 결과를 하나씩 나타낼 수 있다.

Promise.race()

async function process() {
  try {
     const first = await Promise.race([getDog(), getRabbit(), getTurtle()]);
  console.log(first);
  } catch (e) {
    console.log(e);
  }  
}
  • Promise.all()과 사용 방법은 같고, Promise.race()를 사용한다.
  • 등록 된 Promise들 중 가장 빨리 끝나는 것 하나만 결과로 나타낸다. ('토끼')

    📌 Promise.race() 안에 있는 Promise 중 가장 빨리 끝나는 Promise가 에러일 때만 에러로 간주하고, 나머지는 확인 하지 않는다.

profile
룰루랄라! 개발자 되고 싶어요🙈

0개의 댓글