상세 컨텐츠

본문 제목

시베리안 허숙희의 자바스크립트 비기닝 12 (콜백함수 callback)

자바스크립트

by e7e 2023. 6. 9. 22:21

본문

오늘은 익숙해지면 별거 아닌데, 설명하려면 순서가 잘 안나오는 콜백(callback)함수

설명해 보고자 한당! (정말 처음만 이상하징 별거 아니당!)

그냥 나중에(뒤에) 불리는 함수라고 callback이라고 부를 뿐 이름만큼 쉽당

어찌 보면 패션어블한 Refactoring(리팩토링 테크닉)으로도 볼 수 있당

 

먼저 코드를 실행하기 전에 코드에서  structuredClone(객체) 함수가 보이는뎅, 요건

2022년에 새로 포함된 글로벌하게 쓸 수 있는 함수로 객체복사를 할 때 사용한당!

(caniuse.com 에서 확인해 보면 거의 모든 최신브라우져에서 사용가능 하당!)

 

요걸 사용 안하고 console.log(coffeeCup)이라 찍으면, 참조된 객체라 모든 로그가

똑같이 나와서 순서대로 변한 내용을 제대로 체크 못하고 오해 할 수 있당!

객체 복사 함수를 직접 만들 수도 있지만 여기선 일단 참고 편하게 쓰장!

 

커피를 맹글어 박스 단위로 납품하는  회사가 있다고 치장!  커피컵을 담는 박스와

개별 컵은 외주 회사로 부터 납품을 받고, 회사는 커피컵에 커피를 맹글어 넣는 일을

해야 한다고 단순하게 생각하장.  CEO의 이름은 개명해서 콜백다린이당(우앙! 억지당)

암튼 콜백다린 CEO는 업무를 아래처럼  4개의 기능으로 분류했고, 

 

A.  커피컵을 커피 박스에서 1개씩 꺼내는 일

B.  컵에 뜨건 물을 넣는 일

C.  컵에 커피을 넣는 일

D.  컵에 뚜껑을 달아주는 일

 

업무 순서는  (A와B)  => (A와C) => (A와D)  식으로 합리적 의심을 기반으로

(컵1개씩/물) => (컵1개씩/커피) => (컵1개씩/뚜껑) 작업 순으로  현실에서

검증된 패턴을 적용하기로 하였당!  뭔가 대단한 업무설계를 한 기분이당!

 

위 내용을 코드화 해보면 아래와 같을 것이다, 꼭 console 탭에서 

순서대로 결과가 나오는 지 확인하도록 하자(디버깅 습관은 절대 중요하당!)

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
    /*** 외주 업체가 한다고 가정 시작 ***/
    // 커피용기박스 제작 
    var coffeeBox = [];

    // 커피컵 제작(일단 10개만)해서 커피용기에 넣기
    for(var i=1; i<=10; i++){
        var coffeeCup = {
            cupNum:"cup"+i,
            hotWater:"없음",
            coffee:"없음"
        };
        coffeeBox.push(coffeeCup);
    }
    var rslt1 = structuredClone(coffeeBox);
    console.log("coffeeBox 확인1",rslt1); // 항상 결과확인
    /*** 외주 업체가 한다고 가정 끝 ***/


    /*** 울 회사에서 한다고 가정 시작 ***/
    // 커피컵에  뜨거운 물 넣기
    for(var cup of coffeeBox){
        if(cup.hotWater == "없음") cup.hotWater ="채움";
    }
    var rslt2 = structuredClone(coffeeBox);
    console.log("coffeeBox 확인2",rslt2); // 항상 결과확인

    // 커피컵에 커피 넣기
    for(var cup of coffeeBox){
        if(cup.coffee == "없음") cup.coffee ="채움";
    }
    var rslt3 = structuredClone(coffeeBox);
    console.log("coffeeBox 확인3",rslt3); // 항상 결과확인
    
    // 커피컵에 뚜껑 장착
    for(var cup of coffeeBox){
        if(!cup.cover) cup.cover ="장착";
    }
    var rslt4 = structuredClone(coffeeBox);
    console.log("coffeeBox 확인4",rslt4); // 항상 결과확인
    /*** 울 회사에서 한다고 가정 끝 ***/
</script>

 

울 회사에서 하는 부분을 A,B,C,D 4명 일꾼 역할로 가정하고,함수로 흐름을 정리해 보장!

아래와 비슷하게 정리 할 수 있을 것이당! (일단 내 맘이당!~~)

    // A 일꾼 역할이 B,C,D 보다 특별!
    function A(){
        for(var cup of coffeeBox){
            // 물넣기 (B), OR 커피넣기 (C) OR 뚜겅달기 (D) call          
        }
    }

    // B 일꾼
    function B(pCup){
        if(pCup.hotWater == "없음") pCup.hotWater ="채움";
    }

    // C 일꾼
    function C(pCup){
        if(pCup.coffee == "없음") pCup.coffee ="채움";
    }

    // D 일꾼
    function D(pCup){
        if(!pCup.cover) pCup.cover ="장착";
    }

정리하고 보니, A는 혼자서 역할이 끝나지 않는당! B,C,D 중에 1명과 꼭 함께 해야 한당!

(순서도 항상 A가 먼저 시작해야 한당!, B,C,D는 A 뒤에 해야 한당! 그래서  CallBack)

요걸 멋지게 해결하기 위해  A가 매개변수로 B,C,D중 1명을 받으면 좋을 것이당!

매개변수로 함수를 받아도 아무도 뭐라 안한당!

함수 A를 아래 처럼 바꿀 수 있을 것이당 (요때 pFunc가 콜백함수를 가리키는 참조변수가 된당)

A  function을 부르면, A가 뒤(back)에 pFunc를 불러주기 때문이당! 

    // A 일꾼, 다른 일꾼을 매개변수로 받음
    function A(pFunc){
        for(var cup of coffeeBox){
            // 물넣기 (B), OR 커피넣기 (C) OR 뚜겅달기 (D) call
            pFunc(cup);          
        }
    }

 

자아!~~ 그럼 전체 코드를 완성해 보장~~

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
    /*** 외주 업체가 한다고 가정 시작 ***/
    // 커피용기박스 제작 
    var coffeeBox = [];

    // 커피컵 제작(일단 10개만)해서 커피용기에 넣기
    for(var i=1; i<=10; i++){
        var coffeeCup = {
            cupNum:"cup"+i,
            hotWater:"없음",
            coffee:"없음"
        };
        coffeeBox.push(coffeeCup);
    }
    var rslt = structuredClone(coffeeBox);
    console.log("coffeeBox 확인",rslt); // 항상 결과확인
    /*** 외주 업체가 한다고 가정 끝 ***/

    /*** 울 회사에서 한다고 가정 시작 ***/
    // A 일꾼 업무 정의
    function A(pFunc){
        for(var cup of coffeeBox){
            // pFunc는 B나 C, D가 될 수 있당!
            pFunc(cup);          
        }
    }

    // B 일꾼 업무 정의
    function B(pCup){
        if(pCup.hotWater == "없음") pCup.hotWater ="채움";
    }

    // C 일꾼 업무 정의
    function C(pCup){
        if(pCup.coffee == "없음") pCup.coffee ="채움";
    }

    // D 일꾼 업무 정의
    function D(pCup){
        if(!pCup.cover) pCup.cover ="장착";
    }

    // 일 시작 함수 호출
    A(B);
    var rsltWater = structuredClone(coffeeBox);
    console.log("coffeeBox 물",rsltWater); // 항상 결과확인

    A(C);
    var rsltCoffee = structuredClone(coffeeBox);
    console.log("coffeeBox 커피",rsltCoffee); // 항상 결과확인

    A(D);
    var rsltCover = structuredClone(coffeeBox);
    console.log("coffeeBox 뚜껑",rsltCover); // 항상 결과확인

    /*** 울 회사에서 한다고 가정 끝 ***/
</script>

 

눈이 빠른 사람은 바로 눈치 챘을 것이당!, 매개 변수를 3개로 맹글어서 B,C,D를  한번에 넘기는 것이다

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
    /*** 외주 업체가 한다고 가정 시작 ***/
    // 커피용기박스 제작 
    var coffeeBox = [];

    // 커피컵 제작(일단 10개만)해서 커피용기에 넣기
    for(var i=1; i<=10; i++){
        var coffeeCup = {
            cupNum:"cup"+i,
            hotWater:"없음",
            coffee:"없음"
        };
        coffeeBox.push(coffeeCup);
    }
    var rslt = structuredClone(coffeeBox);
    console.log("coffeeBox 확인",rslt); // 항상 결과확인
    /*** 외주 업체가 한다고 가정 끝 ***/

    /*** 울 회사에서 한다고 가정 시작 ***/
    // A 일꾼 업무 정의
    function A(pFunc1, pFunc2, pFunc3){
        for(var cup of coffeeBox){
            // pFunc1 = B, pFunc2 = C, pFunc3 = D
            pFunc1(cup); // 물넣기
            pFunc2(cup); // 커피넣기
            pFunc3(cup); // 뚜껑달기         
        }
    }

    // B 일꾼 업무 정의
    function B(pCup){
        if(pCup.hotWater == "없음") pCup.hotWater ="채움";
    }

    // C 일꾼 업무 정의
    function C(pCup){
        if(pCup.coffee == "없음") pCup.coffee ="채움";
    }

    // D 일꾼 업무 정의
    function D(pCup){
        if(!pCup.cover) pCup.cover ="장착";
    }

    // 일 시작
    A(B,C,D);
    console.log("coffeeBox 최종",coffeeBox); // 항상 결과확인

    /*** 울 회사에서 한다고 가정 끝 ***/
</script>

 

또다른 눈치 빠른 사람은 말할 것이다! 그럼 난 배열에 함수 3개를 담아서 배열을 넘길테얌!

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
    /*** 외주 업체가 한다고 가정 시작 ***/
    // 커피용기박스 제작 
    var coffeeBox = [];

    // 커피컵 제작(일단 10개만)해서 커피용기에 넣기
    for(var i=1; i<=10; i++){
        var coffeeCup = {
            cupNum:"cup"+i,
            hotWater:"없음",
            coffee:"없음"
        };
        coffeeBox.push(coffeeCup);
    }
    var rslt = structuredClone(coffeeBox);
    console.log("coffeeBox 확인",rslt); // 항상 결과확인
    /*** 외주 업체가 한다고 가정 끝 ***/

    /*** 울 회사에서 한다고 가정 시작 ***/
    // A 일꾼 업무 정의
    function A(pFuncArr){
        for(var cup of coffeeBox){
            // pFuncArr이 배열이므로 반복문을 써도 됨!
            pFuncArr[0](cup); // 물넣기
            pFuncArr[1](cup); // 커피넣기
            pFuncArr[2](cup); // 뚜껑달기         
        }
    }

    // B 일꾼 업무 정의
    function B(pCup){
        if(pCup.hotWater == "없음") pCup.hotWater ="채움";
    }

    // C 일꾼 업무 정의
    function C(pCup){
        if(pCup.coffee == "없음") pCup.coffee ="채움";
    }

    // D 일꾼 업무 정의
    function D(pCup){
        if(!pCup.cover) pCup.cover ="장착";
    }

    // 일 시작
    var vFuncArr = [B,C,D]; // 함수 3개 담은 배열
    A(vFuncArr);
    console.log("coffeeBox 최종",coffeeBox); // 항상 결과확인

    /*** 울 회사에서 한다고 가정 끝 ***/
</script>

그렇당! 이해 되었다면 당신 맘대로당! 자유롭게 사용하면 된당!

단지 협업 및 유지보수 관점에서  가독성이라는 것도 생각하면서 하자!

 

사실 아래와 같은 사용법이 좀 더 많이 사용된당!(스스로 익히장!)

위의 내용이 이해되었다면, 이해가 안 될 이유를 도저히 찾을 수 없당!

<!DOCTYPE html>
<meta charset="UTF-8">
<script>
    /*** 외주 업체가 한다고 가정 시작 ***/
    // 커피용기박스 제작 
    var coffeeBox = [];

    // 커피컵 제작(일단 10개만)해서 커피용기에 넣기
    for(var i=1; i<=10; i++){
        var coffeeCup = {
            cupNum:"cup"+i,
            hotWater:"없음",
            coffee:"없음"
        };
        coffeeBox.push(coffeeCup);
    }
    var rslt = structuredClone(coffeeBox);
    console.log("coffeeBox 확인",rslt); // 항상 결과확인
    /*** 외주 업체가 한다고 가정 끝 ***/

    /*** 울 회사에서 한다고 가정 시작 ***/
    // A 일꾼 업무 정의
    function A(pFunc){
        for(var cup of coffeeBox){
            // 요기가 포인트당!
            pFunc(cup); // 콜백함수 call
        }
    }

    // 요번 커피에만 이벤트 상품으로 로제 글자를 새기기로 했당
    // 요번에만 쓸 함수라 구지 미리 정의하지 않았당!~~ 
    A(function(pCub){
        pCub.saleCoffee = "로제이벤트";
    });
    
    console.log("coffeeBox 최종",coffeeBox); // 항상 결과확인
    /*** 울 회사에서 한다고 가정 끝 ***/
</script>

전공자들도 처음엔  콜백을 조금 낯설어 하지만 보통 2~3일 정도 

키보드 두드리다 보면 머리와 손가락의 하모니가 형성된당(눈만 따라가도 OK당)

 

콜백은 특히 비동기 결과완료 이벤트에서 결과처리 함수로 많이 이용되는데,

이것 때문에 콜백을 비동기라 오해하는 사람들이  꽤 있당!

콜백 자체는 동기/비동기와 아무 관련이 없당!~~

 

이해 되었다면 아래 문제를 풀어보길 간절히 바란당. (3+1)*2 = 8

바로 풀렸다면 Good Job! 이당.  

  const add = (x) => x + 1;
  const multiply = (x) => x * 2;
  const compose = (firstF, secondF) => {
    /* 코드 작성해 보세용 */
  };

  const transform = compose(add, multiply);
  alert(transform(3));

 


 

다행이당!, 유튜브 시대라 글을 써도 누가 읽겠엉?, 나만의 메모로 만족하장!

생각했는뎅!, 그래도 몇명씩 찾아와서 읽어준당 고맙고, 감사하고 마니 사랑한당!

어떨 수 없이 그냥 막 마구 쓴당!~~  이것은 중독인가? 가스라이팅인가?

내일은 B가 온다닝, B로 허전함을 달래야 겠당!  I Need B -> INB -> 난 부럽당!

 

 

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

 

관련글 더보기