[JS] 비동기처리와 Promise, Async & Await

심언조·2021년 3월 20일
6

JavaScript

목록 보기
2/2
post-thumbnail

📔 JS에서 비동기처리

자바스크립트에서의 비동기 처리란 어떤 기능이 실행되고 있는 동안 다른 동작을 멈추지 않고 실행하는것을 의미한다.

function makeCoffee(order){
	setTimeout(()=>{
      console.log(`make ${order}☕️`);
    }, 
    Math.floor(Math.random() * 100) + 1) // 임의의 값 생성
}

function getCoffee(){
  makeCoffee('americano');
  makeCoffee('cafe latte');
  makeCoffee('cold brew');
}

getCoffee(); // 출력결과는 어떻게 되는가 ?

위 코드를 비동기로 실행시켰지만 랜덤한 지연시간값을 생성하므로 순서대로 실행시키지는 않는다. 순서를 제어하고 싶다면 어떻게 해야 할까 ? 콜백함수로 비동기 실행을 구현하면 다음과 같이 만들 수 있다.

function makeCoffee(order, callback){
	setTimeout(()=>{
      console.log(`make ${order}☕️`);
      callback();
    }, 
    Math.floor(Math.random() * 100) + 1) // 임의의 값 생성
}

function getCoffee(){
  makeCoffee('americano', ()=>{
  	makeCoffee('cafe latte', ()=>{
      makeCoffee('cold brew', ()=>{
        console.log('End');
      });
    });
  });
}

getCoffee(); // 동작의 순서를 제어할 수 있다.

위 코드에서는 다음에 실행할 함수를 콜백함수로 넘겨주어 순서를 제어할 수 있다. 그러나 다음과 같은 문제가 있다.

😱 콜백 지옥(Callback hell)

위의 경우에서는 3개의 함수만 실행시켰지만 그보다 함수를 더 많이 실행시켜야 한다면 계속 들여쓰기를 해가면서 함수를 콜백으로 넘겨주어야 할 것이고 그렇게 코드를 작성하면 가독성 이 낮아질 뿐 아니라 코드를 관리하기 힘들어진다. 이 문제를 해결하기위해 promise 객체를 사용한다.

📕 Promise 객체

promise객체를 통해 앞에서 살펴본 콜백지옥을 해결할 수 있다. promise 객체는 비동기 작업이 맞이할 완료 또는 실패와 그 결과 값을 나타낸다. promise는 세가지 상태를 가지며 각각의 상태의 종류는 다음과 같다.

  • 대기(pending) : 초기상태
  • 이행(fulfilled) : 연산이 성공적으로 완성됨
  • 거부(rejected) : 연산이 실패함

아래의 코드를 살펴보자.

// promise 생성, 이때 상태는 대기상태
// 이 구문을 생산자(Producer)라고 한다. 
const promise = new Promise((resolve, reject)=>{
  console.log('promise is running...');
  // 어떤 작업을 실행한 후
  somethingWork((error, data)=>{
  	// 실행한 결과가 error 값이라면 reject 실행, 이때 상태가 rejected 로 변한다
    if(error){
      reject(error);
    }
    // 이때 상태는 fulfilled 로 변한다
    else{
      resolve(data);
    } 
  });
});

// 생성한 promise 를 사용한다
// 이 구문은 소비자(Consumer)라고 한다.
// then, catch, finally 를 사용할 수 있다.
promise.then( data => {
  // is Resolved
  // 이 구문은 연산이 성공적으로 실행되었을때 resolve 함수를 통해 실행된다.
  return data;
})
// 위 연산에서 data를 리턴받아 다른 처리를 할 수 있다.
.then( data =>{
  process(data);
})
.catch( error => {
  // is Error
  // 이 구문은 prmoise 가 실해하면 reject 함수를 통해 실행된다.
}).finally(()=>{
  // is finished
  // 이 구문은 promise가 성공하든 실패하든 결과에 상관없이 실행된다.
});

📘 Async & Await

그러나 Promise 또한 콜백 지옥과 같은 구조로 될 가능성이 있다. 예를 들면 then 실행절에서 또 새로운 프로미스를 만들거나 then절이 길어진다면 다시 콜백 지옥과 비슷한 상황에 마주하게 된다. 이와같은 문제를 해결하기 위해 Async, Await가 등장했다. 이를 사용하면 동기식으로 프로그래밍을 하는것 처럼 코드를 작성할 수 있다.

function makeCoffee(order){
  return new Promise((resolve, reject)=>{
    setTimeout(()=>{
      let coffee = `make ${order}☕️`;
      console.log(coffee);
      resolve(coffee);
    }, 
    Math.floor(Math.random() * 100) + 1) // 임의의 값 생성
  }); 
}

async function asyncGetCoffee(){
  // 동기적으로 실행결과를 얻을 수 있다.
  let americano = await makeCoffee('americano');
  let cafeLatte = await makeCoffee('cafe latte');
  let coldBrew = await makeCoffee('cold brew');
}

asyncGetCoffee(); 

Async & Awaitpromise를 대체하여 간단하게 표시하는 것처럼 기존에 존재하는 문법위에, 또는 감싸서 편하게 사용할 수 있는 키워드를 가르켜 Syntactic Suger라 부른다.

📙 여러개의 비동기 동작실행후 결과 처리하기

여러개의 비동기 함수를 실행하고 차례대로 실행에 대한 값을 일괄적으로 처리하거나 제일먼저 끝난 처리에 대한 결과를 반환하려면 Promise.all(), Promise.race() 를 사용할 수 있다.

function runningMan(name){
  let runner = name;
  let runtime = Math.floor(Math.random() * 500); // 임의의 값 생성
  return new Promise((resolve, reject) =>{
    setTimeout(()=>{
      resolve({runner, runtime});
    }, 
    runtime) 
  });
}

function startRace(){
  let one = runningMan('One');
  let two = runningMan('Two');
  let three = runningMan('Three');
  let four = runningMan('Four');
  // 가장 먼저 실행이 완료된 동작에 대한 결과만 실행
  Promise.race([one, two, three, four]).then(({runner, runtime}) =>{
  	console.log(`${runner} is come in first : ${runtime}`);
  });
}

function waitAllRunner(){
  let one = runningMan('One');
  let two = runningMan('Two');
  let three = runningMan('Three');
  let four = runningMan('Four');
  // 모든 실행이 완료된 결과를 순서대로 반환 한다.
  Promise.all([one, two, three, four]).then((values) =>{
    values.forEach(({runner, runtime})=>{
      console.log(`${runner} : ${runtime}`);
    });
  });
}
profile
웹 개발자

0개의 댓글