혼자 적어보는 노트

[Javascript] async await에 대한 이해 본문

Javascript

[Javascript] async await에 대한 이해

jinist 2021. 11. 23. 23:42

async와 await

 

async와 await을 사용하면 프라미스를 좀 더 편하게 사용 할 수 있다.

async를 함수앞에 붙이면 자동으로 프라미스로 반환된다.

 

async 함수

async는 function앞에 위치하며 해당 함수는 항상 프라미스를 반환한다.

async function loadData(){
    return "Hey";
}

loadData().then(console.log);

위의 함수가 실행되면 result가 "hey"인 이행 프라미스가 반환된다.

async function loadData(){
    return Promise.resolve("Hey");
}

loadData().then(console.log); // Hey

위와 같이 async에 프라미스를 반환하는 것도 가능합니다.

async가 붙은 함수는 프라미스를 반환하고 프라미스가 아닌 것은 프라미스로 감싸서 반환하는것이다.

 

await

javascript는 await을 만나면 프라미스가 처리(settled)될 때까지 기다리고 그 이후에 반환이 된다.

예를들어 1초 뒤에 실행되는 프라미스가 있고 그것을 await없이 반환을 시도해보자.

*await는 async함수안에서만 동작한다. 즉 async함수 바깥의 최상위 에서는 await를 사용할 수 없다.

async function example() {
    let promise = new Promise((resolve, reject) => {
      setTimeout(() => resolve("success"), 1000)
    });
  
    let result = promise; 
  
    console.log(result); // Promise {<pending>}
}
  
  example();

위의 코드를 보면 프라미스가 실행되기 전에 result로 promise값을 받아버려서

예상된 결과가 나오지 않는다.

await를 사용해보자.

async function example() {
    let promise = new Promise((resolve, reject) => {
      setTimeout(() => resolve("success"), 1000)
    });
  
    let result = await promise; // 1초 뒤 "success" 출력
  
    console.log(result); 
}
  
  example();

위와 같이 함수를 호출하고 await로 실행이 잠시 중단되었다가 프라미스가 처리되면 실행이 된다.

 

 

아래의 예시와 함께 promise로 작성된 코드를 async로 바꾸어보자

 

[ promise ]

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

function firstLoad(){
    return delay(1000).then(()=>'Jay');
}

function secondLoad(){
    return delay(1000).then(()=>"Jin");
}

function nameLoad(){
    return firstLoad().then(first=>{
        return secondLoad().then(second=>{
            return first + second;
        })
    })
}

nameLoad().then(console.log);

firstLoad 와 secondLoad에 await를 사용하여 각각 1초 뒤에 return값을 받고

그 값에 따라 이름이 합쳐진 결과를 얻기 위한 코드를 작성해보았다.

 

하지만 nameLoad부분에서 return이 복잡하게 되어있어 한번에 이해하기가 힘들어진다.

 

이부분을 해결하기 위해 async await를 사용해보자.

 

[ async await ]

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

async function firstLoad(){
    await delay(1000);
    return 'Jay';
}
async function secondLoad(){
    await delay(1000);
    return 'Jin';
}

async function nameLoad(){
    const first = await firstLoad();
    const second = await secondLoad();
    return first + second;
}

nameLoad().then(console.log);

async와 await을 사용하여 보다 간결하게 코드를 구현해보았다.

await는 promise.then보다 좀더 가독성이 좋으며 사용하기도 편하다.

 

하지만 위 코드를 하면 fist와 second가 각각 1초씩 기다렸다가 출력되서

 nameLoad()가 완료되기까지 총 2초의 시간이 소요된다.

first와 second는 데이터를 받아올 필요가 없고, 겹치는 데이터가 없는 상태인데

이것을 각자 받아올 수는 없을까?

 

 

await 병렬 처리

async function nameLoad(){
    const firstPromise = firstLoad();
    const secondPromise = secondLoad();
    const first = await firstPromise;
    const second = await secondPromise;
    return first + second;
}

nameLoad().then(console.log);

await하지 않고 firstPromise와 secondPromise로 동시에 받아온다음

first와 second에 await를 적용하여 두 개가 완료되었을 때 바로 실행이 되게끔 병렬처리를 하면

nameLoad가 출력되는데에 1초만 소요된다.

 

promise 병렬처리 - Promise.all()

function loadAll(){
    return Promise.all([firstLoad(), secondLoad()])
    .then(name => name.join(''));
}
loadAll().then(console.log);

위와 같이 Promise.all을 사용하여 배열로 두 값을 담아준 후

두 값을 join()시켜주어 노출하는 방식이 있다. await보다 코드가 깔끔하다.

 

 

에러핸들링

await에서의 에러는 throw가 던진 에러를 잡을 때 처럼 try catch를 사용하여 처리할 수 있다.

 

[ try/catch ]

async function example() {
    try{
        let response = await fetch("http://???"); //찾을 수 없는 주소
        let user = await response.json();
    }catch(error){
    	// 에러 발생 시 여기서 표시 가능
        console.log(error);
    }
}
  
example();

try에서는 여러개의 구문을 작성할 수 있으며 response와 user의 에러가 catch에서 잡아서 처리한다.

 

[ .catch ]

async function example() {
        let response = await fetch("http://???"); //찾을 수 없는 주소
        let user = await response.json();

}
  
example().catch(alert);

try/catch를 사용하지 않고 해당 함수에 .catch를 사용하여 에러를 핸들링 할 수도 있다.

 

 

정리

- async함수는 항상 프라미스를 반환한다.

- await는 async함수 안에서만 동작한다.

- 프라미스 앞에 await를 붙이면 프라미스가 처리될 때 까지 기다려준다.

- async/await이 promise.then보다 문법적으로 편하긴 하지만 await는 async함수 밖에서 사용할 수 없기 때문에

then/catch를 추가하여 핸들링 해야 한다.

- 병렬처리를 하려면 promise.all이 좀 더 깔끔하다.

Comments