[Javscript] promise로 콜백지옥 탈출하기

콜백지옥

내가 짠 코드가 바로 콜백지옥인가 보다🤣🤣

$(document).ready(function () {
    console.log("기존 멤버 수 : " + existingMemberNum);
    // ajax로 목록 불러오기
    searchAjax("");
    <c:forEach var="i" items="${partyList}">
        addExistingMembers(${i.emp_code}, "${i.empname}");
        disableCheckbox(${i.emp_code}) // 체크박스를 수정할 수 없도록 상태를 disabled로 수정
    </c:forEach>
});

searchAjax() -> addExistingMembers(code, name) -> disableCheckbox(code) 순으로 실행하고 싶었는데, 순서가 꼬여서 뒤에 두 함수가 제대로 실행되지 않았다.

Promise로 콜백함수 실행하기

사전등록을 해놓으면, 사이트가 오픈된 후에 자동으로 초대이메일이 발송되는 프로그램이 있다고 가정해보자. 철수는 사이트 오픈 전에 사전등록을 해두어서, 오픈 후 초대메일을 받게 되었다. 영희는 사이트가 이미 오픈된 후에야 사전등록을 했는데, 이미 사이트가 오픈된 후이기 때문에 기다리지 않고 바로 메일을 받을 수 있었다.

Promise는 비동기를 수행할 때 콜백함수 대신 유용하게 쓸 수 있는 javascript에 내장된 object이다. 두가지의 핵심개념을 이해하면 편하다.

  • State
    • pending : Promise가 만들어져서 우리가 지정한 operzation이 수행중일 때
    • fullfilled : operation이 완료된 상태
    • rejected: operation이 거부된 상태
  • Producer vs Consumer
    • Producer는 원하는 기능을 수행하고 해당하는 데이터를 만든다.
      • 정상적으로 수행 시 resolve를 반환한다.
      • 오류가 발생하는 경우에는 reject를 반환하고, 에러가 발생하는 이유를 적어두는 것이 좋다.
    • Consumer는 then, catch, finally로 값을 처리한다.
      • then : Promise가 정상적으로 수행했을 경우 resolve 콜백함수를 통해 값을 전달받는다.
      • catch : Promise가 에러 발생 시 reject 콜백함수를 통해 값을 전달받는다.
      • finally : 결과와 상관없이 마지막에 무조건 실행된다.
  1. Producer

    • 새로운 프로미스가 만들어질 때, 전달한 executor라는 콜백함수가 바로 실행된다.
    • 따라서 내부에 불필요한 network 통신이 발생하지는 않는지 유의할 필요가 있다.

    • resolve와 reject를 인자로 받는다.
    const promise = new Promise((resolve, reject) =>{
        // doing some heavy work (network, read files)
        console.log('doing somethingk...');
        setTimeout(() => {
            resolve('ellie');
            // reject(new Error('no network'));
        },2000);
    });
    
  2. Consumers

    promise
        .then((value) => { // 성공했을 때 실행
        	// value는 resolve에서 전달된 'ellie'라는 값이 들어온다.
        	console.log(value);
    	}).catch(error => { // 실패했을 때 실행
        	console.log(error);
    	}).finally(() => { // 성공여부와 상관없이 마지막에 실행
        	console.log('finally');
    	})
    
  3. Promise chaining

    const fetchNumber = new Promise((resolve, reject) => {
        // 서버통신에서는 setTimeout을 자주 쓴다.
        setTimeout(() => resolve(1), 1000);
    })
       
    fetchNumber
    .then(num => num*2)
    .then(num => num*3)
    .then(num => {
        return new Promise((resolve, reject) => {
        	setTimeout(() => resolve(num - 1), 1000);
    	})
    })
    // then은 값을 바로 전달할 수도 있고, promise를 전달할 수도 있다.
    

참고(1) - 매개변수를 하나만 전달하는 경우

매개변수를 하나만 전달하는 경우 생략해도 알아서 매개변수를 전달한다.

// 생략 전
getHen()
	.then(hen => getEgg(hen))
	.then(cook => cook(egg))
	.then(meal => console.log(meal));

// 생략 후
getHen()
	.then(getEgg)
	.then(cook)
	.then(console.log)

참고(2) - 용국쓰 코드

function fn_getSearchEmpList(code){
    return new Promise(function (resolve,reject) {
        var tid= setTimeout(function () {
            $.ajax({
                type : "POST",
                url : "/test/getSearchEmpList",
                data :{code:code},
                dataType :"json",
                success : function(data) {
                    // 수행하는 긴코드 생략
                    $("#empWrapper"+data.team_code).append(html);
                    resolve(data);
                    $(".allcontainer").attr("class","allcontainer w-100");
                }
            });
        },100)
    });
}

fn_getDeptList().then(fn_getteamlist).then(fn_getemplist);

References

드림코딩 엘리 - 프로미스 개념부터 활용까지

Promise - ksh4820 님의 velog

댓글남기기