Javascript/비동기 처리

Async-Await

appmaster 2021. 1. 27. 16:58

Async-Await는 Promise를 기반으로 작동이 된다. 그러기 때문에 Promise를 확실히 공부하고 돌아오는걸 추천한다.

 

 

ex) Promise 객체를 리턴하는 함수

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

 

ex) Promise 객체를 이용해서 비동기 로직을 수행할 때

p(1000).then(ms=>{
    console.log(`${ms} ms후에 실행 된다.`);
});

 

ex) Promise 객체를 리턴하는 함수를 await로 호출하는 방법

const ms = await p(1000);
console.log(`${ms} ms후에 실행 된다.`);

--> await는 비동기처리가 끝날때까지 될때까지 다음줄로 넘어가지 않고 기달렸다가 resolve가 되면 resolve될때 넣어준 인자값(ms)을 return해서 밑으로 이어지게 한다. 이렇게만 사용하면 async안에 감싸져 있지않기때문에 오류가 생긴다.

 

 

 

 

ex) await를 사용하는 경우, 항상 async 함수 안에서 사용되어야 한다.

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

(async function main(){  
    const ms = await p(1000);
    console.log(`${ms} ms후에 실행 된다.`);
})();

--> 이렇게 async가 들어있는 함수가 있을 경우에, 이 함수를 실행하면 그 안에있는 로직이 끝날때 까지 프로그램이 종료되지않고 중간에 한줄한줄 내려갈때 await가 걸려있으면 비동기가 끝날때까지 잠시 기다렸다가 정상적으로 끝나면 resolve 인자값 ms를 받아와서 console.log로 이어서 진행하게 된다.

async await의 좋은점은 비동기처리를 로직코드를 밑으로 흘러가게 볼 수 있다는것이 가장 큰 장점이다.

 

 

 

ex) Promise 객체가 rejected 된 경우의 처리를 위해 try catch를 이용한다.

function p(ms) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            //resolve(ms);
            reject(new Error('reason'))
        }, ms)
    });
}

(async function main(){  
    try{
        const ms = await p(1000);
        //정상적으로 들어왔다면 ms인자를받고 처리한다.
    }catch(error){
        console.log(error);
    }
})();

new Error('reason')이라는 객체가 catch(error)로 들어온다. 이런식으로 어떤 비동기처리에서 resolve와 reject를 try catch로 처리하는게 일반적으로 사용하는 형태이다.

 

 

 

 

ex) async function에서 return되는 값은 Promise.resolve 함수로 감싸서 리턴된다.

function p(ms) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            //resolve(ms);
            reject(new Error('reason'))
        }, ms)
    });
}

async function asyncP(){
    return 'Mark';
}

(async function main(){  
    try{
        const name = await asyncP();
        console.log(name)
    }catch(error){
        console.log(error);
    }
})();

이렇게 되면 try값에 들어가게 된다는것을 알 수 있다.

 

 

 

 

function p(ms) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(ms);
            //reject(new Error('reason'))
        }, ms)
    });
}

async function asyncP(){
    const ms = await p(3000);
    return 'Mark' + ms;
}

(async function main(){  
    try{
        const name = await asyncP();
        console.log(name)
    }catch(error){
        console.log(error);
    }
})();
//출력값
Mark3000

소스코드해석:

asyncP가 호출되면서 처음에 await에 걸려서 밑으로 계속 실행되지않고 p를 먼저 해결하려고 할것이다. function p에서 resolve와 reject둘중에 하나로 불릴때까지 기다리고 선택한후에 불리면서 그다음 return 'Mark'로 넘어가게 된다. 다음과 같이하면 asyncP에 선언한 p(3000) 때문에 3초있다가 실행되는모습을 볼 수 있게 된다. 그리고 function p에서 얻어온값도 같이 출력할 수 있게 된다.

 

 

 

 

ex) error 의 전파

function p(ms) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            //resolve(ms);
            reject(new Error('reason'))
        }, ms)
    });
}

async function asyncP(){
    const ms = await p(3000);
    return 'Mark' + ms;
}

(async function main(){  
    try{
        const name = await asyncP();
        console.log(name)
    }catch(error){
        console.log(error);
    }finally{
        console.log('end');
    }
})();
//출력값
Error: reason
    at <anonymous>:5:20
end

다음의 소스코드를 실행하게 되면, function p는 reject로 가게되는데 그 reject된값이 asyncP로 throw되면서 asyncP에서 try catch문을 사용하지 않고도 async function main()으로 가게 되면 알아서 catch(error)로 들어가 error값이 출력이 되게 된다. 이것을 통해서 본인이 어디서 error를 처리해야하는지 알게 된다. 그리고 마지막에 꼭 처리가 되는 finally에 들어가 'end'를 출력하게 된다.