Ep4. Promise 객체

hyobin·2023년 1월 6일
5
post-thumbnail

안녕하세요🤗

이번시간에는 비동기 작업을 다룰 때 사용되는 Promise객체에 대해 개념부터 사용법까지 다뤄보도록 하겠습니다.

비동기적 처리

저번시간에 배웠던 자바스크립트의 비동기적 처리에 대해 다시 한 번 이야기해보겠습니다.

우리는 setTimeout 함수를 이용해 작업을 비동기적으로 처리했었고, setTimeout함수는 아래와 같이 콜백함수와 ms단위의 시간을 파라미터로 입력받는 함수라고 배웠었습니다.

setTimeout(() => {
    console.log("5초만 기다리세요");
}, 5000);

그렇다면, 이번에는 자바스크립트의 비동기 처리를 실제로 구현해봅시다.

5초 후에 전달받은 값에 100을 더한 값이 출력되는 간단한 비동기 함수를 구현해보겠습니다.

const sum = (value, callback) => {
    setTimeout(() => {
        callback(value + 100);
        console.log("===종료===");
    }, 5000);
};

console.log("===시작===");

sum(121, (res) => {
    console.log(res);
});

위의 코드의 실행 결과를 살펴봅시다.

실행 후 제일 먼저 console.log("===시작===") 이 출력됩니다.

그 다음 sum 함수가 실행되고, 숫자 121과 함수를 파라미터로 받습니다.

위의 sum 함수에서 value 값으로 121을, callback 값으로 한 개의 값을 받아 출력하는 함수를 전달 받았기때문에,
setTimeout 의 콜백함수에서 121에 100을 더한 값인 221이 5000ms 즉, 5초 후에 출력되는 것을 확인할 수 있습니다.

===시작===
221
===종료===

221이 출력된 이후 "===종료===" 가 출력됩니다.

여기까지 이해를 하셨다면, 자바스크립트의 비동기 처리에 대해 완벽하게 이해를 하셨을 것입니다.

그렇다면, 이번에는 전달받은 숫자에 1초마다 10을 3번 더한 다음 그 결과값을 출력하는 작업을 setTimeout으로 구현해보겠습니다.

const sum = (value, callback) => {
    setTimeout(() => {
        callback(value + 10);
    }, 1000);
};

sum(100, (res) => {
    console.log(res);
    sum(res, (res) => {
        console.log(res);
        sum(res, (res) => {
            console.log(res);
        });
    });
});

자바스크립트에서 비동기 작업을 처리 할 때에는 우리가 앞서 배웠다시피 setTimeout 함수와 함께 콜백함수를 사용하게 되는데요,
지금처럼 비동기적으로 처리해야하는 작업이 많을 수록 위의 코드와 같이 가독성이 매우 좋지 않고, 복잡한 코드를 작성해야합니다.

sum(100, (res) => {
    console.log(res);
    sum(res, (res) => {
        console.log(res);
        sum(res, (res) => {
            console.log(res);
        });
    });
});

우리는 이렇게 복잡하게 생긴 코드를 콜백 지옥 이라고 부르며, 이 콜백 지옥은 Promise 객체를 이용해 해결할 수 있습니다.

Promise

Promise 는 자바스크립트의 내장 객체로, 다음과 같이 생성 가능합니다.

const promise = new Promise();

Promise 객체는 이렇게 new 키워드와 생성자를 사용해 생성해야합니다.

그럼 이제 Promise 객체의 사용법을 알아보겠습니다.

const executor = (resolve, reject) => {
    //코드
};
const promise = new Promise(executor);

executor 라는 함수가 Promise 객체에 전달되는 것을 볼 수 있는데요,

Promise 객체에 전달되는 함수는 executor(실행함수) 라고 부릅니다.

이 실행함수는 Promise 생성자에 반드시 들어가야 하는 함수이며, 비동기 처리의 주체가 되는 함수입니다.

5초 후에 실행되는 비동기 함수를 promise 객체를 이용해 구현해보겠습니다.

const executor = (resolve, reject) => {
    setTimeout(() => {
        console.log("5초만 기다리세요");
    }, 5000);
};
const promise = new Promise(executor);

위의 코드를 실행하면 5초 후에 "5초만 기다리세요" 가 출력되는 것을 확인할 수 있습니다.

이렇게 executor 함수는 생성과 동시에 즉시 자동으로 실행됩니다.

resolve와 reject

지금까지 Promise 객체의 사용법에 대해 배워보았습니다.

Promise 객체의 사용법에 대해 배우면서, 설명 없이 작성만 하고 그냥 넘어간 부분이 있는데요, 바로 executor 함수의 파라미터인 resolve와 reject 입니다.

resolve와 reject은 자바스크립트에서 자체 제공하는 콜백으로, executor는 비동기처리가 성공하면 resolve를, 실패한다면 reject를 호출합니다.

비동기 처리 작업은 항상 성공할 수도, 실패할 수도 있기 때문에 resolve와 reject 둘 중 하나를 반드시 호출해야합니다.

Promise 내부 프로퍼티

더 자세한 설명을 위해 Promise 객체의 내부 프로퍼티들을 살펴보겠습니다.

Promise 객체는 다음과 같은 두 가지 내부 프로퍼티를 갖습니다.

  1. state - 대기(pending), 이행(fulfilled), 거부(rejected)
  2. result - undefined, value, error

Promise는 맨 처음 대기(pending) 상태와 undefined의 값을 가지고 있다가, executor 가 호출하는 함수에 따라 state와 result가 변화됩니다.

그림에서 볼 수 있듯이, executor는 처음엔 대기 상태에 있다가, resolve가 호출 될 경우 promise의 상태를 이행으로 변경하고, reject가 호출 될 경우 상태를 rejected로 변경합니다.

대기상태에 있을 경우, 처음엔 undefined의 값을 갖고있다가 resolve가 호출이 되면 value로, reject가 호출이 되면 error 로 변하게됩니다.

이렇게 Promise 객체의 상태는 resolve와 reject를 통해 변하지만, 한 번 변경된 상태는 더 이상 변하지 않아 처리가 끝난 Promise 객체에 resolve 또는 reject를 호출하면, 무시됩니다.

resolve 와 reject 사용하기

resolve와 reject가 호출 될 때 Promise 의 상태가 어떻게 변화하는지에 대해 배워보았으니, 이번에는 resolve와 reject의 사용법에 대해 배워보겠습니다.

resolve

5초 후에 "5초만 기다리세요" 를 출력하는 비동기 함수를 resolve를 이용해 구현해보겠습니다.

const executor = (resolve, reject) => {
    setTimeout(() => {
        resolve("5초만 기다리세요");
    }, 5000);
};

const promise = new Promise(executor);
promise.then((res) => {
    console.log(res);
});

이렇게 executor 함수에서 비동기 처리된 결과 값을 반환할 때에는, 파라미터로 받은 resolve 콜백함수에 결과값을 전달하면 됩니다.

그리고 relove 콜백함수에 전달된 값은 Promise 객체의 then 메서드를 이용해 사용할 수 있고, then 메서드에는 executor 함수에서 전달한 값이 파라미터로 전달됩니다.

위의 코드를 살펴보면 먼저 executor 함수가 promise 생성과 동시에 자동 실행되었고, 이후 resolve("5초만 기다리세요") 가 호출이 되었습니다.

이때, promise 객체의 state와 result는

  1. state : pending -> fulfilled
  2. result : undefined -> "5초만 기다리세요"

로 변화되었다는 것을 알 수 있습니다.

reject

이번에는 reject를 이용해 비동기 처리가 실패했다고 가정해보고, reject 함수의 사용법을 알아보겠습니다.

const executor = (resolve, reject) => {
    setTimeout(() => {
        reject("실패했습니다.");
    }, 5000);
};

const promise = new Promise(executor);
promise
    .then((res) => {
        console.log(res);
    })
    .catch((error) => {
        console.log(error);
    });

마찬가지로, 위의 코드에서 promise 객체의 state와 result는 다음과 같이 변하게 되어, 위의 코드를 실행한 결과 "실패했습니다" 가 나오는 것을 확인 할 수 있습니다.

  1. state : pending -> rejected
  2. result : undefined -> "실패했습니다."

그리고 reject는 Promise 객체의 catch 메서드를 통해 실패했을 때 수행할 작업을 설정 할 수 있습니다.

콜백지옥을 해결하는 Promise 객체

마지막으로, 우리가 Promise 객체를 배우기 전 겪었던 콜백지옥 함수를 지금까지 배운 Promise 객체를 사용해서 작성해보겠습니다.

콜백지옥을 설명했던 예시 그대로, 숫자 100을 시작으로 130이 될 때 까지 1초에 10씩 더해지는 함수를 구현해봅시다.

const sum = (num) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const value = num + 10;
            if (value === 140) {
                reject("ERROR");
                return;
            }
            console.log(`값: ${value}`);
            resolve(value);
        }, 1000);
    });
};

sum(100)
    .then(sum)
    .then(sum)
    .then(sum)
    .catch((e) => {
        console.error(e);
    });
값 : 110
값 : 120
값 : 130
ERROR

위의 코드 실행 결과, 다음과 같이 3초가 지난 후 값이 130까지 출력이 되고, 그 이후 값이 140이 되면 ERROR 가 출력됩니다.

이렇게 위의 코드처럼 함수에서 Promsie 객체를 반환하도록 하면, 더욱 유연한 비동기 처리 작업을 할 수 있고,

Promise 객체를 이용해 이전에 작성했던 콜백지옥을 훨씬 간단하고 가독성있는 코드로 작성할 수 있습니다.

next

이번 시간에는 자바스크립트의 또 다른 비동기 처리 방식인 Promise 객체의 개념과 사용법에 대해 배워보았습니다.

다음 시간에는 오늘 배운 이 Promise 객체를 더욱 쉽고 직관적으로 작성할 수 있게 도와주는 async/await에 대해 배워보도록 하겠습니다.

감사합니다😄

🙏참고 & 출처

https://ko.javascript.info/promise-basics

0개의 댓글