반응형

앞서 살펴본 약속(Promise)에 대해서 자세히 알아보자.

 

- Promise.all():  Promise의 배열을 매개변수로 삼고, 배열의 모든 Promise가 fulfil일 때만 새로운 fulfil Promise 오브젝트를 반환


- .finally(): Promise의 결과가 fulfilled 인지 rejected인지 관계 없이 Promise가 완료된 후 최종 코드 블럭을 실행하려는 경우 사용

 

이벤트 리스너와 다른점
- 한번에 성공/실패 중 하나의 결과값을 가진다. 하나의 요청에 두 번 성공하거나 실패할 수 없다.

또한 이미 성공한 작업이 다시 실패로 돌아갈 수 없고 실패한 작업이 성공으로 돌아갈 수 없다.

Promise() 생성자 사용
- 주로 Promise기반이 아닌 구식 비동기 API코드를 Promise기반 코드로 만들고 싶을 경우 사용.
- resolve(): Promise가 resolve상태일 때 전달할 값을 지정할 수 있다.
- reject(): Promise가 reject상태일 때 전달할 값을 지정할 수 있다.

 


async 키워드

 - 함수 앞에 async 키워드를 사용하면 반환받는 값은 Promise 객체가 된다.(상태:fulfil) 즉, 해당 함수를 Promise로 바꾼다.

 - async 키워드를 class/object의 메서드에 사용하여 Promise 객체를 반환하게 만들 수 있다.

 

function hello() {
    return "Hello"
}
console.log(hello());

async function asyncHello() {
    return "Hello"
}
console.log(asyncHello());

async 키워드를 사용하여 Promise 객체로 전달받을 수 있다.

 


 

await 키워드

 - 웹 API를 포함하여 Promise를 반환하는 함수를 호출할 때 사용할 수 있다. 

 - JavaScript 런타임이 키워드가 선언된 라인에서 비동기 코드를 일시 중지하여 비동기 함수 호출이 결과를 반환할 때 까지 기다리게 하며 외부의 다른 동기 코드는 실행될 수 있도록 한다. 작업이 완료되면 선언된 라인 아래의 코드는 계속 이어져서 실행된다.

 - async function 안에서만 사용할 수 있다.

 - async/await는 Promise의 상위에 만들어져 있기 때문에 Promise의 모든 기능을 사용할 수 있다.

 - 동기화 코드처럼 보이게하여 가독성이 올라간다.

async function asyncHello() {
    return greeting = await Promise.resolve("Hello");
  };
  
asyncHello().then(alert);

 

 

async/await 주의점

- async/await는 어떤 면에서는 정말로 동기적으로 행동한다.

  -> 함수 블럭에 여러 개의 await 키워드를 사용하면 Promise가 fulfilled되기 전까지 다음 await을 차단한다.(그 동안 다른 태스크는 계속 실행이 되지만 정의한 함수 내에서는 동기적으로 작동)

이는 바로 이어지는 수 많은 Promise에 의해 느려질 수 있다는 것을 의미한다.

(각 await는 이전의 작업이 끝날 때까지 기다리기 때문인데 Promise 체이닝과 혼동하지 말자)

function timeoutPromise(interval) {
    return new Promise((resolve, reject) => {
      setTimeout(function(){
        resolve("done");
      }, interval);
    });
};

async function timeTest() {
    await timeoutPromise(3000);
    await timeoutPromise(3000);
    await timeoutPromise(3000);
}

let startTime = Date.now();
timeTest().then(() => {
  let finishTime = Date.now();
  let timeTaken = finishTime - startTime;
  alert("Time taken in milliseconds: " + timeTaken);
})

timeTest의 동작은 3초마다 종료되며 총 9초의 시간이 걸리게 된다.

 

하지만 아래의 형태로 먼저 비동기 함수는 자유롭게 실행되도록 두고 변수가 사용가능 할 때 꺼내쓰도록 리팩토링 하면 총 시간이 3초로 줄어들게 된다.

async function timeTest() {
    const timeoutPromise1 = timeoutPromise(3000);
    const timeoutPromise2 = timeoutPromise(3000);
    const timeoutPromise3 = timeoutPromise(3000);
  
    await timeoutPromise1;
    await timeoutPromise2;
    await timeoutPromise3;
}

해당 문법을 사용하고 성능이 떨어지기 시작하면 위의 상황을 의심해봐야 한다.

 

 

[참고자료]

MDN WEB DOCS - Graceful asynchronous programming with Promises

MDN WEB DOCS - Making asynchronous programming easier with async and await

 

 

 

반응형

+ Recent posts