프로그래밍/Javascript

자바스크립트 Promise 예제를 통해 쉽게 이해하기

변태 개발자 아미넴 2020. 12. 4.

비동기 처리의 한 방법인 콜백 함수를 다루면서 동기와 비동기에 대한 개념도 함께 설명을 드렸는데요.

잘 모르시는 분은 아래 포스팅 먼저 읽어 보시길 바랄게요 :)

sangminem.tistory.com/275

 

[자바스크립트] 콜백 함수 예제를 통해 개념 및 원리 쉽게 이해하기

자바스크립트를 배운 지 얼마 안 되신 분이라면 콜백 함수를 많이 헷갈려 하실 수 있는데요. 차근차근 설명을 해 보도록 하겠습니다. 목차 동기와 비동기 의미 동기는 하나의 요청이 오면 완료

sangminem.tistory.com

 

지금부터 비동기 처리의 또 다른 방법인 Promise에 대해 알아 보겠습니다.

 

목차

     

    Promise란 무엇인가

    비동기 함수를 동기 처리하기 위해 고안한 객체입니다.

    비동기 작업이 완료된 이후에 다음 작업을 연결시켜 진행할 수 있는 기능을 가지고 있습니다.

    작업 결과 따라 성공 또는 실패를 리턴하며 결과 값을 전달 받을 수 있습니다.

     

     

    Promise의 3가지 상태 및 처리 흐름

    pending(대기) : 처리가 완료되지 않은 상태

    fulfilled(이행) : 성공적으로 처리가 완료된 상태

    rejected(거부) : 처리가 실패로 끝난 상태

     

    Promise 처리 흐름 [출처] MDN web docs

    일단 이 부분은 참고적으로만 알아 두셔도 되는데 간단히 얘기를 하면 Promise 객체가 비동기 함수의 처리 상태를 보고 완료되었는지 판단하여 성공 여부에 따라 다음 처리를 다르게 수행할 수 있도록 해 줍니다.

     

     

    잘못된 비동기 방식 예제

    setTimeout 함수는 비동기 방식으로 처리되는 함수 중 하나 입니다.

    따라서 setTimeout 함수를 통해 1초 뒤에 작업을 수행하면 완료될 때까지 기다렸다가 다음 작업을 수행하는 것이 아니라 다음 작업이 먼저 실행이 되는 현상이 발생합니다.

    function goToSchool() {
        console.log("학교에 갑니다.");
    }
    
    function arriveAtSchool_asis() {
        setTimeout(function() {
            console.log("학교에 도착했습니다.");
        }, 1000);
    }
    
    function study() {
        console.log("열심히 공부를 합니다.");
    }

    예제로 학교에 가서 공부하는 과정을 메시지로 출력하는 3가지 함수를 작성해 보았습니다.

    학교에 도착하는 것은 1초 뒤라고 가정하여 setTimeout 함수를 적용하였습니다.

     

    3가지 함수를 차례로 실행해 보겠습니다.

    goToSchool();
    arriveAtSchool_asis();
    study();

     

    역시 올바르지 못한 결과가 나왔죠.

    학교에 도착하기도 전에 열심히 공부를 하는 사태가 발생했습니다.

    그리고 1초 뒤에 학교에 도착했다는 메시지가 출력이 됩니다.

     

     

    Promise 기본 예제

    Promise를 어떻게 적용했는지 먼저 보도록 할게요.

    function arriveAtSchool_tobe() {
        return new Promise(function(resolve){
            setTimeout(function() {
                console.log("학교에 도착했습니다.");
                resolve();
            }, 1000);
        });
    }

    구조를 살펴보면 사실 콜백 함수를 사용한 방법과 유사한 형태에서 Promise 객체를 적용하여 리턴한 정도 입니다.

     

    이 함수를 다음과 같이 호출하여 사용할 수 있습니다.

    goToSchool();
    arriveAtSchool_tobe().then(function(){
        study();
    });

    일단 학교에 가는 함수는 동일하게 호출하면 되구요.

    arriveAtSchool_tobe 함수는 Promise 객체를 리턴하는데 Promise는 then이라는 메서드를 가지고 있고 그 메서드 파라미터에 콜백 함수를 대입하면 앞서 resolve()라고 정의했던 구문이 실행이 되는 구조입니다.

    구현의 차이는 있지만 아직까진 직접 콜백 함수를 작성한 것과 의미상으로 큰 차이는 없어 보입니다.

     

    일단 결과를 확인해 보면 다음과 같이 정상적으로 수행된 것을 확인할 수 있습니다.

    학교에 도착했다는 메시지는 1초 뒤에 출력이 되고 그 이후에 열심히 공부한다는 메시지가 출력됩니다.

     

     

    Promise 고급 예제

    기본 예제에서는 전부 다루지 않았지만 Promise 객체는 2가지의 콜백 함수를 가집니다.

    하나는 앞서 언급한 fulfilled 상태에서 실행되는 resolve 함수이고 다른 하나는 rejected 상태일 경우 실행되는 reject 함수입니다.

    function arriveAtSchool_tobe_adv() {
        return new Promise(function(resolve, reject){
            setTimeout(function() {
                var status = Math.floor(Math.random()*2);
                if(status === 1) {
                    resolve("학교에 도착했습니다.");
                } else {
                    reject("중간에 넘어져 다쳤습니다.");
                }
            }, 1000);
        });
    }
    
    function cure() {
        console.log("양호실에 가서 약을 발랐습니다.");
    }

    랜덤 함수를 이용하여 숫자 0 또는 1을 status 변수에 담은 후에 1일 경우 성공, 0일 경우 실패라고 가정하고 각각의 메시지를 콜백 함수로 넘겨 주었습니다.

    또한 실패일 경우 처리해 줄 cure 함수를 하나 작성하였습니다.

     

    작성한 함수를 다음과 같이 수행해 보겠습니다.

    goToSchool();
    arriveAtSchool_tobe_adv()
    .then(function(res){
        console.log(res);
        study();
    })
    .catch(function(err){
        console.log(err);
        cure();
    });

    먼저 마찬가지로 학교에 가는 함수를 실행했구요.

    학교에 도착하는 함수는 성공 또는 실패하는 두 가지 경우를 만들었죠.

    성공 시에는 then 메서드가 실행되어 resolve 함수를 통해 넘겨준 문장을 실행하게 됩니다.

    만약 실패하여 reject 함수가 실행되는 경우는 catch 메서드를 통해 reject 콜백 함수를 수행하게 됩니다.

    reject일 때는 then 메서드가 실행되지 않으므로 성공, 실패를 각각 분리해서 처리할 수 있게 되는 것입니다.

    콜백 함수 작성 방법에서도 콜백 함수를 2개 넘겨주면 비슷하게 처리가 가능합니다.

     

    두 가지 경우의 결과를 비교해 보겠습니다.

    각각의 경우 다른 처리를 해 줄 수 있다는 것이 명확하게 보입니다.

     

    사실 reject인 경우는 명시적으로 에러 객체를 만들어 넘겨주는 것이 더 일반적이고 올바른 방법입니다.

    reject(new Error("중간에 넘어져 다쳤습니다."));
    

     

    catch구문으로 예외 처리를 해주지 않으면 이런 식으로 에러가 발생합니다.

    이렇게 되면 프로그램 완성도가 떨어져 보일 뿐만 아니라 빨간 글씨는 좀 거부감이 들죠.

     

    따라서 catch 구문으로 에러를 인지하여 처리를 해 주는 것이 좋습니다.

    에러 관련 정보를 보여주고 적절한 처리를 할 수 있게 됩니다.

     

    성공, 실패 콜백 함수를 다음과 같이 호출할 수도 있습니다.

    someFunc()
    .then(successCallback, failCallback);

    단일 호출에서는 별 문제가 없지만 아래에서 설명할 체이닝 기법 사용 시에는 catch 메서드 사용을 권장합니다.

     

    Promise의 장점

    그럼 대체 Promise의 장점은 무엇일까요?

     

    Promise 연결하기(체이닝)

    이제부터 그 장점이 하나씩 보이기 시작합니다.

     

    다음과 같이 비동기로 연산이 이루어지는 Promise 객체가 적용된 add 함수가 있다고 가정해 보겠습니다.

    add(1,1)
    .then(function(res){ // res: 2
        return res + 1; // 2 + 1 = 3
    })
    .then(function(res){ // res: 3
        return res * 4; // 3 * 4 = 12
    })
    .then(function(res){ // res: 12
        console.log(res); // 12 출력
    });

    then 메서드에서 값을 return 키워드를 사용하면 결과 값이 기본 자료형이 아닌 Promise 객체로 반환되기 때문에 이와같은 체인 형식이 가능하게 됩니다.

     

    then 메서드 내에서 직접 Promise를 return 할 수도 있습니다.

    goToSchool()
    .then(function(){
        return arriveAtSchool();
    })
    .then(function(){
        return studyHard();
    })
    .then(function(){
        return eatLunch();
    });

    각각의 함수가 Promise 객체를 리턴하는 비동기 작업이라고 가정한다면 위와 같이 then 메서드를 연속적으로 사용하여 순차적인 작업을 할 수도 있습니다.

     

    체이닝 기법을 활용함으로써 콜백 함수 사용 시 발생할 수 있는 콜백 지옥에서 탈출이 가능합니다.

     

    Promise 예외(에러) 처리

    Promise는 예외 처리에서도 장점이 있습니다.

    goToSchool()
    .then(function(){
        return arriveAtSchool();
    })
    .then(function(){
        return studyHard();
    })
    .then(function(){
        return eatLunch();
    })
    .catch(function(){
        leaveEarly();
    });

    학교에 가는 도중에 다치거나 공부를 하다가 열이 나거나 점심을 먹다가 체하는 일이 생기더라도 마지막 catch 구문에서 조퇴하는 것으로 한 번에 처리가 가능하다는 의미입니다.

    이 경우 최초 발생하는 rejected 상태의 작업만 처리하고 구문을 빠져 나오게 됩니다.

     

     

    마무리

    그리고 비교적 최근에 나온 Promise를 다루는 async await 구문이 있는데 비동기 함수를 동기 함수처럼 다룰 수 있어 매우 깔끔하고 유용하게 사용할 수 있는 방법입니다.

    다음 포스팅에서 다룰 예정이니 기대해 주세요!

     

    더 다양하고 복잡한 기능이 있지만 쓸 일이 많지 않고 저도 거의 써 보지 않았기 때문에 일단 이 정도만 알아 두셔도 큰 문제는 없어 보입니다.

    잘 사용하지 않는 심화된 내용까지 한 번에 이해하려고 하는 것은 비효율적이므로 필요할 때 잘 정리된 포스팅이나 공식 문서를 찾아 보시는 것을 추천드립니다.

     

    감사합니다 :)

     

    [자바스크립트] async / await 예제

     

    [자바스크립트] async / await 예제

    목차 async / await 란 무엇인가 Promise 객체를 좀 더 쉽게 다룰 수 있게 고안된 문법입니다. 이해가 어렵지 않고 사용법도 쉽게 익힐 수 있습니다. 다만 ECMAScript 2017에서 표준으로 정의된 문법이므로

    sangminem.tistory.com

     

    BIG

    댓글4

    💲 추천 글