본문 바로가기
개발/JavaScript

자바스크립트 async await

by 피로물든딸기 2021. 8. 3.
반응형

자바스크립트 전체 링크

 

프로미스 외에도 async await을 이용하면 프로미스를 반환할 수 있다.

 

아래의 코드를 보자.

async function getData(data) { 
    return data;
}

console.log(getData("test 1"));

getData("test 2", 3000).then(data => console.log(data));
getData("test 3", 1000).then(data => console.log(data));

 

getData("test 1")이 Promise를 반환하는 것을 알 수 있다.

getData가 Promise를 반환하기 때문에 then을 이용하여 반환된 값을 출력할 수 있다.


await은 async 함수 내에서 사용한다.

await은 프로미스의 처리가 완료될 때까지 기다린다.

즉, 비동기 처리를 순차적으로 처리할 수 있게 도와준다.

 

async test 함수에서 await이 없다면 아래의 코드는 test 2가 먼저 출력된 후, test 1이 출력된다.

function sleep(ms) {
  const loopTime = Date.now() + ms;
  while (Date.now() < loopTime) {}
}

function getData(data, delay) {
  sleep(delay);
  return new Promise((resolve) =>
    setTimeout(() => {
      console.log({ data, delay });
      resolve(data);
    }, delay)
  );
}

async function test() {
  const test1 = getData("test 1", 3000);
  const test2 = getData("test 2", 1000);

  console.log(test1, test2);
  
  return { test1, test2 };
}

test().then((data) => console.log(data));

또한 test1, 2의 getData가 완료되기 전에 test1과 test2의 로그를 출력하여 Promise<pending>이 나온다.

그리고 async test의 반환값을 then을 이용하여 출력하니 Promise가 나오는 것을 알 수 있다.

getData가 완료되지 않았는데, 코드가 실행되어서 나타나는 현상이다.

 

이제 getData 앞에 await 코드를 추가해보자.

const test1 = await getData("test 1", 3000);
const test2 = await getData("test 2", 1000);

 

getData가 순차적으로 실행되었고, 반환값도 정상적으로 출력되는 것을 알 수 있다.

then이 연쇄적으로 사용되면 가독성이 떨어질 수 있는데, 이런 경우는 async await을 사용하는 것이 좋다.


비동기 함수 getData를 사용할 때, 순서를 지킬 필요가 없다면, 동시에 실행하는 것이 성능에 도움이 된다.

이런 경우, getData를 먼저 실행하고, await을 나중에 사용하면 병렬로 실행하는 효과를 낼 수 있다.

async function test() {
  const test1 = getData("test 1", 3000);
  const test2 = getData("test 2", 1000);
  const value1 = await test1;
  const value2 = await test2;

  console.log(value1, value2);

  return { value1, value2 };
}

 

수정 전에는 3초 후 test 1이 출력되고, 다시 1초 뒤에 test 2가 출력된다.

수정 후에는 1초 후 test 2가 출력되고, 다시 2초 뒤에 test 1이 출력된다.

이후 모든 작업이 완료되고 value1, value2가 console.log에서 출력된다.

 

Promise all로 병렬처리를 할 수 있으므로 아래와 같이 한 줄로 줄일 수도 있다.

async function test() {
  const [value1, value2] = await Promise.all([getData("test 1", 3000), getData("test 2", 1000)]);

  console.log(value1, value2);

  return { value1, value2 };
}

Thenablethen 메서드를 가지고 있는 객체, 즉 프로미스처럼 동작할 수 있는 객체다.

async await은 then 메서드를 가진 객체를 프로미스처럼 다룰 수 있다.

function sleep(ms) {
  const loopTime = Date.now() + ms;
  while (Date.now() < loopTime) {}
}

function getData(data, delay) {
  sleep(delay);
  return new Promise((resolve) =>
    setTimeout(() => {
      console.log({ data, delay });
      resolve(data);
    }, delay)
  );
}

class MyThenable {
  then(resolve, reject) {
    resolve(getData("test 1", 3000));
  }
}

const myThenable = {
  then: function (resolve, reject) {
    resolve(getData("test 2", 1000));
  },
};

async function test() {
  let value1 = await new MyThenable();
  let value2 = await myThenable;
  
  console.log(value1, value2);
}

test();

 

then 메서드가 아니라면 아래의 로그가 나온다.

class MyThenable {
  then1(resolve, reject) {
    resolve(getData("test 1", 1000));
  }
}

 

value1이 단순히 MyThenable 객체를 출력한 것을 알 수 있다.

 

Thenable 객체는 Promise에서도 사용가능하다.

//test();

Promise.resolve()
  .then(() => new MyThenable())
  .then((data) => console.log(data));
  
Promise.resolve()
  .then(() => myThenable)
  .then((data) => console.log(data));

반응형

댓글