Cute Bow Tie Hearts Blinking Pink Pointer

백엔드/Node.js

[nodejs] promise, then, await 구동 순서, 사용 이유 완벽 이해하기

청포도 에이드 2022. 1. 28. 22:31
728x90

promise는 비동기 처리를 위해 있는 객체이다.

 

 

여기서 동기처리, 비동기처리란?

 

 

예를 들어, 집안일을 한다고 가정해보자.

 

동기식 :  세탁기를 돌리고, 빨래가 종료되면 그제서야 바닥에 청소기를 돌린다.

 

비동기식 : 세탁기를 돌려놓고, 빨래가 돌아가는 동안, 바닥 청소하고 설거지하다가 세탁기가 종료되면 세탁물을 꺼낸다.

 

즉, 비동기는 코드의 효율성을 극대화 할 수 있는 처리방식이다! 

 

 

아래의 코드를 보자. setTimeout은 대표적인 비동기식 함수이다!!

(일단, 구동은 하는데 백그라운드에 대기만 시켜놓고 작업이 끝나면 실행을 해준다.)

 

const pr = new Promise((resolve, reject)=>{
    setTimeout(()=>{
        resolve('hello promise');
    },1000);
});

function test() {
    return 'hi';
}
console.log(test()); // hi

console.log(pr); // pending

 

promise는 단순하게 그냥 비동기식으로 구동하기 위해 사용하는 객체이다.

생성자를 이용해서 pr을 프로미스 객체로 만들어주는 것!!

 

만약 동기식이라면 hi, hello promise

 

이렇게 출력이 되겠지만, pr라는 promise 객체는 구동 후 백그라운드에 박혀있다가 1초(1000) 뒤에 실행이 되기때문에

 

정작 출력은 hi, pending 이런식으로 나온다.

 

이렇게 나옴

 

그 이유?

 

test 함수를 만났으니 일단 hi가 출력되는 건 당연하다.

 

근데 곧바로 test 함수가 끝나자마자 (아주빠른 시간) 만난 게 console.log(pr)이다.

 

pr (promise 객체) 은 코드가 구동되고 1초 뒤에 실행이 될 예정인데, 1초가 안 돼서 백그라운드에 쳐박혀있는데,

 

console.log가 1초 이따 나온다는 애를 자꾸 부르니까 아직 없다고. 실행되지 않았다고 나오는 표시이다. -> <pending>

 

 

이해를 돕기 위한 응용 코드를 보자. (async 사용)

 

필요한 사전 지식

 

async란? 함수 앞에 붙여서 Promise 객체화 시켜주어, 비동기식으로 구동할 거라고 컴퓨터에게 알려주는 함수

 

const pr = new Promise((resolve, reject)=>{
    setTimeout(()=>{
        resolve('hello promise');
    },1000);
});

function test() {
    return 'hi';
}
console.log(test()); // hi

async function test2() {
    return 'hi';
}
console.log(test2()); // Promise { 'hi' }

console.log(pr); // Promise { <pending> }

pr.then(data=>{
    console.log(data); // hello promise
});

 

일단 출력 결과를 먼저 보자.

 

 

test()함수는 마찬가지로 그냥 아무 문제없이 hi로 출력이되었음.

 

문제는, test2()부터인데, 이 함수 앞에 async를 입력해주었기때문에 promise객체가 되었기 때문에,

객체의 형태로 출력되는 것이다.

 

여기까진 입력순서대로 출력이 되었고,

 

console.log(pr)부터 역시 pending이 출력된다. 방금 전 위에 있는 예제의 설명과 동일하게,

 

코드 구동 시작하고 1초 뒤에 실행할 건데(그래서 백그라운드에서 대기중인데), 자꾸 부르니까. 없다고, 대기중이라고

pending을 출력하는 것이다.

그 다음, 처음보는 부분!

 

pr.then(data=>{
    console.log(data);

 

 

then이란?

 

비동기식 코드가 백그라운드에서 나오면(대기가 끝나면, 즉 종료되면) 그 때 이어서 실행하겠다.

 

따라서 마지막 코드를 해석해보면

 

pr이라는 변수의 프로미스객체가 종료되면(구동하고 1초가 지나면)

 

그 때 return값 을 data라는 변수에 넣어주고 그 값을 출력하겠다. 라는 의미이다.

 

따라서 맨 위에 적었던 pr의 결과 값인 "hello promise"가 출력되는 것이다. 

 

 

 

심화 예제 1 (사실 나한테만 심화임)

 

윗부분은 (test(), test2()) 동일

 

const pr = new Promise((resolve, reject)=>{
    setTimeout(()=>{
        resolve('hello promise');
    },1000);
});

function test() {
    return 'hi';
}
console.log(test()); // hi

async function test2() {
    return 'hi';
}
console.log(test2()); // Promise { 'hi' }

console.log(pr); // Promise { <pending> }

pr.then(data=>{
    console.log(data); // hello promise
});

function test3() {
    let i = 0;
    pr.then(data=>{
        i++;
        console.log(data); // hello promise
        
    });
    return i;
}

console.log(test3());

 

출력결과를 미리 보자.

 

이렇게 나온다.

hi, promise hi, promise pending까지는 전 문제와 동일하고(console.log(pr)까지), 그 뒤부터 설명하겠다.

 

전과 달리, 

 

pr.then(data=>{
    console.log(data);

 

의 출력값이 바로 나오지 않는 이유는 역시 pr이 백그라운드에서 빠져나와(1초동안 갇혀있음) 실행되기 전에 test3()이 먼저 실행되기 때문이다!!

 

여기서 의문점 ) 아니 그럼 i++ 해줬는데 1이 출력되지 않고, 왜 0이 출력되는가?

 

출력 결과

function test3() {
    let i = 0;
    pr.then(data=>{
        i++;
        console.log(data);
        
    });
    return i;
}

 

------------------------------

 

let i =0으로 정의된 상태에서,

pr.then~ 구문은 pr이 종료되면 그때서야 실행하기 때문이다. 그래서 i가 0일 때 이미 출력되고 나서, 그제야 i이 뒤늦게 +1 된 것이다.

 

만약 1을 출력하고 싶다면? 

 

console.log(data)

바로 밑줄에 console.log(i)를 추가해주면 된다. (살짝 야매인게 밑에 return 때문에 0이 먼저 출력 되고 1이 나옴 그래서 다른 방법을 소개하겠다)

 

심화 예제 2 (사실 나한테만 심화임)

1을 맘편하고 가독성있고 쉽게 출력하는 법

 

심화 예제 1 코드에서 test3()을 아래코드로 치환해주면 된다.

await 설명아래에

const pr = new Promise((resolve, reject)=>{
    setTimeout(()=>{
        resolve('hello promise');
    },1000);
});

function test() {
    return 'hi';
}
console.log(test()); // hi

async function test2() {
    return 'hi';
}
console.log(test2()); // Promise { 'hi' }

console.log(pr); // Promise { <pending> }

pr.then(data=>{
    console.log(data); // hello promise
});

async function test3() {
    let i = 0;
    let podo = await pr;
    i++;
    console.log(i); // 1
    return i;
}

console.log(test3());

 

await이란? 

 

 

※ promise 객체에서 await을 만나면, promise 객체가 끝날 때까지 await구문에서 코드가 멈춘다!

 

 

출력결과 미리 확인하기

 

 

async function test3() {
    let i = 0;
    let podo = await pr;
    i++;
    console.log(i); // 1
    return i;
}

console.log(test3());

 

코드 해석 : i를 0으로 정의한다. await pr을 변수 podo에 저장해두고, 위에 있는 pr이라는 promise 객체가 실행되어 종료될 때까지 그 아래코드를 실행하지 않는다.(= pr이 종료되자마자 아래 코드를 실행한다.)

 

 

console.log(test3())을 실행했을 때, test3()이라는 프로미스 객체 함수가 await때문에 중도에 멈췄기 때문에

 

console엔 promise <pending>이 찍힐 수밖에 없다.

 

그리고 지정했던 1초가 지나고 나서야, pr이 종료되면 await이후 구문인 i++부터 실행된다.

 

따라서 i+1이 되고 1이 찍히게 된다.

 

 

728x90