Callback 함수 문제를 해결 - Promise

Junghyun Park·2020년 12월 4일
0
post-thumbnail

필요성(기존 nested call back 함수를 사용하는 경우 문제점)

데이터 송수신 장애, 물리적 제약 등 여러 요인에 의해 delay가 발생하는 경우에는, 비동기 함수를 사용하여 delay 시간 동안에도 다른 코드 실행을 하도록 해야하는데, 여러 함수의 return값이 chain 형태로 엮여 있는 경우, 일반 call back function을 nested 식으로 하게 되면, 디버그도 어렵고, 가독성이 매우 좋지 않아지는 문제가 발생할 수 있음

이러한 문제를 해결하기 위한 방법으로 생겨난 개념이 Promise임.
Promise는 기본적으로 비동기 처리를 마치 동기인 것 처럼 처리하는데, 최종결과를 일반 형식으로 return하지 않고, 상태를 포함한 Promise Object 형식으로 return 함.

문법(syntax)

먼저, new Promise Object를 생성하여 해당 함수의 콜백 함수로서 비동기 처리 함수를 넣는다(ex> new Promise((resovle, reject) => {... }) 다음으로, 해당 함수를 호출하면서, data를 return 받는데 성공하는 경우 .then((data) => {...})을 통해 하고 싶은 처리를 정의하고, chain 형태로 구현하고자 하면, 마지막 각 처리에 해당하는 함수 마지막에 새로운 함수 호출 구문을 return하고 .then으로 이어 붙임 (하단 예시 코드 참조)
만일, 오류일 경우 처리는 .catch()로 처리

활용예시

경우 1 - nested callback function

const fakeRequestCallback = (url, success, failure) => {
    const delay = Math.floor(Math.random() * 4500) + 500;
    setTimeout(() => {
        if (delay > 4000) {
            failure('Connection Timeout :(')
        } else {
            success(`Here is your fake data from ${url}`)
        }
    }, delay)
}


fakeRequestCallback('books.com/page1',
    function (response) {
        console.log("IT WORKED!!!!")
        console.log(response)
        fakeRequestCallback('books.com/page2',
            function (response) {
                console.log("IT WORKED AGAIN!!!!")
                console.log(response)
                fakeRequestCallback('books.com/page3',
                    function (response) {
                        console.log("IT WORKED AGAIN (3rd req)!!!!")
                        console.log(response)
                    },
                    function (err) {
                        console.log("ERROR (3rd req)!!!", err)
                    })
            },
            function (err) {
                console.log("ERROR (2nd req)!!!", err)
            })
    }, function (err) {
        console.log("ERROR!!!", err)
    })

비동기 함수(setTimeout)을 처리하기 위해, fakeRequestCallback이라는 동일함수를 nested 형태로 입력하고 있음
=> 복잡하고, 가독성이 낮다.

경우 2 - nested Promise 적용

const fakeRequestPromise = (url) => {
    return new Promise((resolve, reject) => {
        const delay = Math.floor(Math.random() * (4500)) + 500;
        setTimeout(() => {
            if (delay > 4000) {
                reject('Connection Timeout :(')
            } else {
                resolve(`Here is your fake data from ${url}`)
            }
        }, delay)
    })
}


fakeRequestPromise('yelp.com/api/coffee/page1')
    .then(() => {
        console.log("IT WORKED!!!!!! (page1)")
        fakeRequestPromise('yelp.com/api/coffee/page2')
            .then(() => {
                console.log("IT WORKED!!!!!! (page2)")
                fakeRequestPromise('yelp.com/api/coffee/page3')
                    .then(() => {
                        console.log("IT WORKED!!!!!! (page3)")
                    })
                    .catch(() => {
                        console.log("OH NO, ERROR!!! (page3)")
                    })
            })
            .catch(() => {
                console.log("OH NO, ERROR!!! (page2)")
            })
    })
    .catch(() => {
        console.log("OH NO, ERROR!!! (page1)")
    })

promise 객체 생성 함수로 변경 & nested .then() , .catch() 적용
=> nested callback function 사용 경우랑 별반 차이 없어 보임

경우 3 - 축약형 Promise 적용

fakeRequestPromise('yelp.com/api/coffee/page1')
    .then((data) => {
        console.log("IT WORKED!!!!!! (page1)")
        console.log(data)
        return fakeRequestPromise('yelp.com/api/coffee/page2')
    })
    .then((data) => {
        console.log("IT WORKED!!!!!! (page2)")
        console.log(data)
        return fakeRequestPromise('yelp.com/api/coffee/page3')
    })
    .then((data) => {
        console.log("IT WORKED!!!!!! (page3)")
        console.log(data)
    })
    .catch((err) => {
        console.log("OH NO, A REQUEST FAILED!!!")
        console.log(err)
    })

동일 준위에서 .then을 사용하고, catch()는 중복제거되어 하나로 대체
=> 훨씬 간소하고 유지 보수에 유리

profile
21c Carpenter

0개의 댓글