상세 컨텐츠

본문 제목

Promise(약속) 모르면 바보옹(비동기)

자바스크립트

by e7e 2024. 1. 8. 21:51

본문

설마 아직도 Promise(약속)를 모르는 사람들이 현업에도 있다닝!~~

중학교 시절 친구에게 똥침을 당했던 기억만큼 놀라우리만큼 아프공,아프당~~

항상 그렇진 않지만 역시 별거 아니당. 띠간을 쪼메 투자해 보장!

 

마냑 콜백을 모른다면, 여기서 더 읽어도  ㅠㅠ 크게 의미가 없으닝....

2023.06.09 - [자바스크립트] - 시베리안 허숙희의 자바스크립트 비기닝 12

글을 먼저 차분히 읽고 콜백을 이해하고 다시 오장!(시름 그냥 일콩, 콜백 익장)

 

보통 비동기는 실행시간이 필요해서, 결과를 바로 return받지 못해, 실행완료 되었을 때,

해당 결과를 콜백함수의 매개변수로 넘겨주는 빵씩으로  마니 사용하는 뎅(AJAX생각?)

 

요거이 옴팡지게 운이 나쁘면, 비동기 안에 비동기 안에  비동기 식 반복 .....,

콜백함수 안에 콜백함수 안에 콜백함수..... 형태로 가독성이 눈알을 뺑뺑 돌리는 

레벨까지 초 상승을 하게 되는 뎅, 요따위 상태를 Hell Of Callback (콜백지옥) 이라 

부른당.  요걸 해결하고자  도입된 것이 Promise 인데, 사실 BlueBird 에 있던 걸

인기가 좋아서 자바스크립트 안에 Native로 넣어 버린 거시었던 거시당!

 

최종적으로는 async/await만 알아도 잘 쓸  수 있지만, async/await가 Promise를

기반으로 동작하고 있으닝, Promise를 들여다 볼 명분은 충분하당.

 

"우리 내일 만나기로  약속행!",   음... 약속은 지금 당장 결과를 알 수 없당.

내일이 되어야 약속대로 되었는지, 약속이 깨어졌는지 알  수 이땅.

그래서 이름이 Promise(비동기 함축, 약속시간까지 당신은 분명 다른 일을 할거당)당

 

첨 보면 무자허갱 낯선데, 자주 보면 별거 업스닝, 일단 Promise 생성자에서 띠작하장!

    new Promise((resolve, reject) => {
    	// 아래 둘 중에 1개만 불러야 함
        resolve("성공시 전달내용"); // 성공시 값을 전달하기 위해 사용
        reject("실패시 전달내용");  // 실패시 값을 전달하기 윟해 사용
    })

 

생성자에 콜백함수가  매개변수로 넘어가공 , 콜백함수는 다시 2개의 콜백함수를

받는뎅(말만 어려움..), resolve는 약속대로 실행 되었을 때 호출해서 사용하공,

reject는 약속대로 안되었을 때 호출해서 사용하면 된당, 곧  배타적인 성공과 실패

2가지를 동시에 가질  수 없으닝, resolve나 reject 둘 중에 1개만 불러야 행!(오켕?)

resolve와 reject 콜백함수명은 매개변수이니 당신 입맛대로 이름을 바꾸어도 됨!

 

아직은 느끼미 느끼지 못해 남극 황제펭귄이 부러울 만큼 뜬금없이 춥당!.

아래 샘플을  복사/붙여넣기로 실행해서, 느끼미 끝자락을 와락 잡아보장!

<!DOCTYPE html>
<meta charset="UTF-8">
<script>

    // Promise를 생성해서 리턴하는 함수
    const f_promise1 = function () {
        return new Promise((res, rej) => {
            res("약속대로 잘 되었어용^-^");
        })
    }

    f_promise1().then((result) => {
        alert("resolve에는 then이 불려용");
        console.log("체킁1:", result);
    })

    const f_promise2 = function () {
        return new Promise((res, rej) => {
            reject("약속이 뿌라져써용ㅠㅠ");
        })
    }

    f_promise2().catch((pRslt) => {
        alert("reject에는 catch가 불려용");
        console.log("체킁2:", result);
    })

</script>

 

실행해 보면 결과가 땅근 비동기당. 아마도 설명이 쪼메 피료할거시당.

Promise를 리턴하는 함수에는 then과 catch를 붙일 수 있는뎅, 이 역시

매개변수(넘어온 값을 받음) 1개를 가진 콜백함수가 오공(오켕?)

res 쓰면 then이 호출되공, rej를 쓰면 catch가 호출 된당(뭔가 익숙하당)

그렇당 자바의 try catch finally가 생각난당.

당근이당,  아래 처럼 finally도 있당. (매개변수 없는 콜백이 매개변수당!!)

<!DOCTYPE html>
<meta charset="UTF-8">
<script>

    // Promise를 생성해서 리턴하는 함수
    const f_promise2 = function () {
        return new Promise((res, rej) => {
            reject("약속이 뿌라져써용ㅠㅠ");
        })
    }

    f_promise2().catch((pRslt) => {
        alert("reject에는 catch가 불려용");
        console.log("체킁2:", result);
    }).finally(() => {
        alert("난 왜 무조건 불령 억울행!!");
    })

</script>

느끼믄 멀지만, 그래도 먼가 느껴진단당!

 

비동기 처리를 위해서 나왔다고 거만을 떠닝, 비동기  대표주자  AJAX를 Promise로 

포장해보장. (요따구로 하는 걸 멋진맬로 Promisefy라 한당, 그냥 그렇당)

 

먼저 AJAX로 불러올 데이타를 아래 껄 복사/붙여넣기 해성 맹글장.

 

newJeans.json

[
    { "name": "민지", "birth": "2004-05-07", "nationality": "대한민국" },
    { "name": "하니", "birth": "2004-10-06", "nationality": "호주|베트남" },
    { "name": "다니엘", "birth": "2005-04-11", "nationality": "호주|한국" },
    { "name": "해린", "birth": "2006-05-15", "nationality": "대한민국" },
    { "name": "혜인", "birth": "2008-04-21", "nationality": "대한민국" }
]

 

같은 폴더에 아래 내용을 복사/붙여넣기로 맹글어넣공, 실행해 보장!

(꼬옥 console.log를 확인하는 센스쟁이 필요!)

ajaxPromisefy.html

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
    // AJAX 프로미스파이(프로미스화) 함수
    const ajaxPromise = () => {
        return new Promise((res, rej) => {
            let xhr = new XMLHttpRequest();
            xhr.open("get", "newJeans.json", true);  // 성공할 URL
            //xhr.open("get", "newJeans1.json", true); //  실패할 URL
            xhr.onreadystatechange = () => {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    let recResult = JSON.parse(xhr.responseText); // 배열이니깡 JSON이얌
                    res(recResult);  // 성공했어용, then 진행해 주삼
                }
            }
            // 실패 처리(onloadend이벤트는 마지막에 무조건 발생, status값을 이용 에러처링)
            xhr.onloadend = () => {
                if (xhr.status != 200) {
                    let myError = {    // 억지로 
                        status: xhr.status,
                        message: xhr.statusText
                    };
                    rej(myError);  // 실패했어용, catch 진행해 주삼
                }
            }
            xhr.send();
        })
    }

    // 함수 테스텅
    ajaxPromise().then((rslt) => {
        alert("누가 먼저 뜰가용 E7E ?");
        console.log("떵공:", rslt);
    }).catch((rslt) => {
        console.log("띨패:", rslt);
    }).finally(() => {
        console.log("결론", "재미없는뎅 재밌어용~~");
    })

    alert("누가 먼저 뜰가용 금수저?");
</script>

 

console.log를 확인하면 결과가 잘 와 이쓰믈 확인 할 수 있당.(then실행)

현재의 xhr.open을 주석처리하공, 실패할 URL 라인의 주석을 제거하고 실행!

console.log를 확인하면,catch가 처리되었음을 확인할 수 있당.

 

하지만 아직 느끼미 엄청 강하지는 아늘거시당.

new Promise 생성자 안의 자바스크립트 ajax부분을 jQuery $.ajax로 

바꾸는 연습을 추천한당. (관계업는 거 같은뎅, 이상하게 도우미 될 거시당!)

사실 다행인 건 Promise를 직접 만들 일은 거의 없고, 사용만 잘해도 훌륭하당!

쓰다 보면 어느 순간 만들 수 있음도 느낄 수 있당.(미더랑!)

 

이왕 온 기메 쪼메 더 나아가 보장!

개발자들은 처음엔 Promise가 마니 이써보여 환영하는 분위기 였으나,

곧 then , catch 지옥도 누나페 이씀을 깨닫고 불평이 하늘을 가른당.

그래서 나왔당. async/await 세트가 최종 구세주당! 

(요것만은 꼬옥 익히장!)

 

함수 호출 부분만 바꾸면 되지만, 누니 느린 사람들이 있어  중복이 많지만

해가 깔리지 않게, 전체 코드를 붙여본당.

asyncawait.html

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
    // AJAX 프로미스파이(프로미스화) 함수
    const ajaxPromise = () => {
        return new Promise((res, rej) => {
            let xhr = new XMLHttpRequest();
            xhr.open("get", "newJeans.json", true);  // 성공할 URL
            //xhr.open("get", "newJeans1.json", true); //  실패할 URL
            xhr.onreadystatechange = () => {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    let recResult = JSON.parse(xhr.responseText); // 배열이니깡 JSON이얌
                    res(recResult);  // 성공했어용, then 진행해 주삼
                }
            }
            // 실패 처리(onloadend이벤트는 마지막에 무조건 발생, status값을 이용 에러처링)
            xhr.onloadend = () => {
                if (xhr.status != 200) {
                    let myError = {    // 억지로 
                        status: xhr.status,
                        message: xhr.statusText
                    };
                    rej(myError);  // 실패했어용, catch 진행해 주삼
                }
            }
            xhr.send();
        })
    }


    // async 와 await는 꼭 세트롱, await는 Promise를 리턴하는 함수앞에 사용가능
    // alert 뜨는 순서에 주목해 보장!
    const fTest = async () => {
        let rslt = await ajaxPromise();
        alert("누가 먼저 뜰가용 E7E ?");
        console.log("결과는:", rslt);
    }
    fTest();  // 함수 호출

    alert("누가 먼저 뜰가용 금수저?");
</script>

 

정신을 차려야 한당! (중요한 뽀인또당)

async / await 세트는 엄청 칭찬을 마니 받았는뎅, 아래가 이유당!

함수 안에서 await를 써서 비동기를 동기처럼 사용하였당.

이러면 비동기가 아니지 않나용? 질문이 나오는 순간 alert 순서 결과를 생각!!!

함수자체가 비동기로 동작!!!!(Good! Good! Good!)  어케 오켕?

async / await 세트 결단코 자주 써서 소네 새겨버리장

 

이해가 잘 안된 사람은 몇번 더 들여다 보아야 할 거시며,

이해가 된 사람에겐 유명한 axios 라이브러리를 흉네낸 아래 소스가 결단코

도우미 되지 않을리가 없지 않지 않겠는강 싶당!

 

axiosMane.html

<!DOCTYPE html>
<meta charset="UTF-8">
<script>

    // axios 흉네내깅
    const axios = {} // 네임스페이스용 그냥 빈 객체
    axios.get = pURL => {    // get 메소드 추강
        return new Promise((res, rej) => {
            let xhr = new XMLHttpRequest();
            xhr.open("get", pURL, true);
            xhr.onreadystatechange = () => {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    let recResult = JSON.parse(xhr.responseText);
                    res(recResult);
                }
            }
            xhr.onloadend = () => {
                if (xhr.status != 200) {
                    let myError = {
                        status: xhr.status,
                        message: xhr.statusText
                    };
                    rej(myError);
                }
            }
            xhr.send();
        })
    }

    const fTest = async () => {
        let rslt = await axios.get("newJeans.json");  // 뽀인똥!!!
        console.log("결과는:", rslt);
    }
    fTest(); 
</script>

결과는 아래와 같을지어랑.

이해 되었다면 괘니 axios.post도 만들어 보면 좋겠단 생각이 든당

실제 axios는 더 많은 기능(서버, 클라이언트 양쪽에서 사용가능)을 가지고 있당!

 

참고로 Promise 생성자를 안 쓰고, Promise.resolve(), Promise.reject() 식으로도 쓸 수 있는데,

Promise 동작원리를 세부적으로 기피 알지 못하면, 곤경에 빠지게 되닝,

개인적으로 사용을 권장하지 않고, 그냥 new Promise() 식으로 생성자로 사용하길 권장해용!!~^-^

 

 

 

 

프로그램을 잘 짜는 사람을 동경할 필요는 없당.

세월이 흐르면, 결국 잘하는 부분 못하는 부분이 구별되어

서로의 도움이 필요함을 알게 될 테니,

 

그래서 난 금수저를 지금도 동경한당!~~

 

https://www.youtube.com/watch?v=QvtBDsqqOHE

 

관련글 더보기