티스토리 뷰

JavaScript

Promise와 async/await

ljy98 2022. 1. 27. 22:55

1. 콜백지옥

2. Promise

3. async/await


1. 콜백지옥

[그림 1] 콜백지옥(Callback Hell)

콜백(Callback)은 다른 함수의 실행이 끝난 뒤 실행되는 함수이다. 콜백지옥은 JavaScript를 이용한 비동기 프로그래밍시 발생하는 문제로서, 함수의 매개 변수로 넘겨지는 콜백 함수가 반복되어 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상을 말한다.

 

[그림 2] 콜백지옥 예시

위의 스크립트는 apple go, apple end, orange go, orange end, strawberry go, strawberry end 순서로 출력되고, 마지막으로 Mission Complete!가 출력되도록 만든 것이다. apple, orange, strawberry 이렇게 depth가 3개 밖에 없어서 지옥까지는 아니지만, 콜백지옥이 이러한 원리로 생성된다는 것을 알고 넘어가면 되겠다.

 

time 변수에 parseInt는 뒤의 소수점을 없애고 정수 부분만 남기는 역할을 한다. Math.random()은 0과 1 사이의 랜덤한 수를 출력한다. 완전하게 랜덤한 수는 아니지만, 반복 주기가 매우 길기 때문에 거의 랜덤에 가깝다고 생각하면 된다. 

 

Math.random()*10  → 0.0000000000 ~ 9.9999999999 숫자 하나를 랜덤으로 출력

parseInt(Math.random()*10)+1 → 1 ~ 10 자연수를 랜덤으로 출력

(parseInt(Math.random()*10)+1)*1000 → 1000 ~ 10000 사이 1000의 배수를 랜덤으로 출력

 

[그림 3] 콜백지옥 예시에 대한 출력 결과

node call.js로 파일을 실행했을 때 출력되는 순서는 [그림 3]과 같다.

 

 

2. Promise

콜백지옥에 대한 해결 방안으로 Promise가 있다. Promise는 자바스크립트 비동기 처리에 사용되는 객체이다. 자바스크립트의 비동기 처리는 '특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 특성'을 말한다.

 

[그림 4] Promise

Promise는 주로 서버에서 받아온 데이터를 화면에 표시할 때 사용한다. 

 

Promise의 상태(states)에는 3가지가 있다. 여기서 말하는 상태는 프로미스의 처리 과정을 의미한다. new Promise()로 프로미스를 생성하고 종료할 때까지 3가지 상태를 갖는다.

  • Pending (대기) : 비동기 처리 로직이 아직 완료되지 않은 상태
  • Fulfilled (이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
  • Rejected (실패) : 비동기 처리가 실패하거나 오류가 발생한 상태

 

[그림 5] Promise, fulfill/reject

먼저 new Promise() 메소드를 호출하면 대기(Pending)상태가 된다.

new Promise();

 

new Promise() 메소드를 호출할 때 콜백 함수를 선언할 수 있고, 콜백 함수의 인자는 resolve, reject이다.

new Promise(function(resolve, reject) {
    // ...
});

 

콜백 함수의 인자 resolve를 아래와 같이 실행하면 이행(Fulfilled) 상태가 된다.

new Promise(function(resolve, reject) {
    resolve();
});

그리고 이행 상태가 되면 then()을 이용하여 처리 결과 값을 받을 수 있다.

 

콜백 함수의 인자 reject를 아래와 같이 실행하면 실패(Rejected) 상태가 된다.

new Promise(function(resolve, reject) {
    reject();
});

그리고 실패 상태가 되면 실패한 이유(실패 처리의 결과 값)를 catch()로 받을 수 있다.

 

 

3. async/await

function 앞에 async를 붙이면 해당 함수는 항상 프로미스를 반환한다. 프로미스가 아닌 값을 반환하더라도 이행 상태의 프로미스(resolved promise)로 값을 감싸 이행된 프로미스가 반환되도록 한다.

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

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

위의 예시를 보면 test() 함수와 test2() 함수 둘다 return 값이 'hi'이지만, test2() 함수 앞에는 async가 있기 때문에 Promise { 'hi' }를 출력한다.

 

await는 async 함수 안에서만 동작한다. 자바스크립트는 await 키워드를 만나면 프로미스가 처리(settled)될 때까지 기다리고, 결과는 그 이후에 반환된다.

 

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

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
        console.log(i); // 1
    });
    return i;
}

console.log(test3()); // 0

위의 출력 순서는 Promise { <pending> }, 0, hello promise, hello promise, 1이다. 더 정확하게는, Promise { <pending> }, 0이 먼저 출력되고 1초 뒤 pr이 실행되고 hello promise, hello promise, 1이 출력된다.

 

이제 async, await이 들어간 함수와 비교해보겠다.

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

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

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

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

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

위의 출력 순서는 Promise { <pending> }, Promise { <pending> }, hello promise, 1이다. 더 정확하게는, Promise { <pending> }, Promise { <pending> }이 먼저 출력되고, 1초 뒤 pr이 실행된 다음 hello promise, 1이 출력된다.

 

await은 '기다리다'라는 말 그대로 프로미스가 처리될 때까지 함수 실행을 기다리게 만든다. 프로미스가 처리되기를 기다리는 동안 엔진이 다른 스크립트를 실행하거나 이벤트를 처리하는 등의 일을 할 수 있기 때문에 CPU 리소스가 낭비되지 않는다.

 

await는 promise.then보다 좀 더 세련되게 프로미스의 result 값을 얻을 수 있도록 해주는 문법이다. promise.then보다 가독성이 좋고 쓰기도 쉽다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함