[ JavaScript ] 콜백함수와 익명함수

exceed_96·2024년 1월 22일

JavaScript

목록 보기
2/18
post-thumbnail

아무런 생각없이 쓰고 있던 콜백함수와 익명함수의 동작원리에 대해서 공부해보자

리액트나 넥스트나 바닐라 자바스크립트로 프로젝트를 하다보면 콜백함수와 익명함수를 셀 수 없이 많이 쓰는데 해당 함수들은 어떤 역할을 하며 어떤 용도로 쓰일까?



1. 콜백함수


1.1 콜백함수란?

콜백함수는 어떤 함수의 인수로 함수가 전달된 함수이다.

즉, 인수로 전달된 함수를 콜백함수라고 한다.

인수로 전달된 함수는 전달받은 함수 내부에서 호출할 수 있다.

function multi(x, y, z, add) {
  return add(x, y) * z;
}

const add = (x, y) => {
  return x + y;
};

function result(x, y, z, add) {
  console.log(multi(x, y, z, add));
}

result(1, 2, 3, add);

위와같이 "result"함수 호출 인수부분에 "add"함수를 인수(콜백함수)로 전달하고 해당 인수는 또 "multi"함수의 내부로 전달하는 방식이다.

그럼 "result" -> "multi" -> "add" 순서대로 함수가 실행되게 된다.



function multi(x, y, z, add) {
  return add(x, y) * z;
}

function result(x, y, z, add) {
  console.log(multi(x, y, z, add));
}

result(1, 2, 3, function (x, y) {
  return x + y;
});

위와같이 익명함수도 함수의 인수로 전달할 수 있다.

보통 콜백함수는 일회성 함수인 경우가 많아서 익명함수를 많이 사용한다.

일반함수는 메모리를 상시 차지하고 있지만 익명함수는 한 번만 사용하는 함수로 만들어졌기 때문에 동작하는 시간 외에는 메모리를 차지하고 있지 않아서 자원관리에 효율적이다.



// 일반함수
function normalFunction (){
}


// 익명함수
function (){}


// 익명 화살표 함수
() => {}


1.2 콜백함수의 장, 단점



1.2.1 장점

  • 함수를 인수로 전달하기 때문에 함수를 정의함에 있어서 가독성에 강한 면모도 있다.
    • 다만 과도한 콜백은 이게 역효과가 나서 콜백지옥에 빠질 수 있다.
  • 함수를 정의하지 않고 익명함수로 인수를 전달할 수 있다.
  • 비동기 처리 방식의 문제점을 해결할 수 있다.
    • 비동기는 특정 코드의 실행을 기다리지 않고 다음 로직을 바로 실행시키는 즉, 병렬처리를 한다.
    • 이럴 경우, 비동기 작업에 따른 결과를 적용시켜줘야 하는 로직이 있는데 이때 콜백함수를 사용해서 해당 작업이 끝날때까지 기다린 후, 콜백함수를 실행시키게 할 수 있다.


1.2.2 단점

  • 콜백지옥에 빠지기 쉽다.

  • 에러 처리가 어렵다.



1.3 콜백함수의 사용사례

  • addEventListner

    const changeButton = document.querySelector(".changeTitleHandler");
    const title = document.querySelector(".title");
    
    changeButton.addEventListener("click", () => {
        console.log("event active");
    	title.innerText = "change!!!";
    });

    이벤트감지 메서드인 addEventListner의 두번째 인수로 콜백함수가 들어간다.


  • 고차함수

    const numberArr = [1, 2, 3, 4, 5];
    
    const changeNumberArr = numberArr.map((el) => {
    	return el * 2;
    });
    
    console.log(changeNumberArr);

    고차함수란, 함수를 인자로 전달받거나 혹은 해당 함수를 통해서 결과를 반환해주는 메서드를 뜻한다.
    고차함수의 종류에는 map, forEach, sort, find, reduce, filter 등등이 있다.


  • setTimeOut, setInterval

    setTimeout(() => {
      console.log("timeout : hello!");
    }, 3000);
    
    console.log("helloTimeout");
    
    setInterval(() => {
      console.log("setInterval : hello!!!!");
    }, 1000);
    
    console.log("helloInterval");


    비동기 처리 함수인 setTimeout, setInterval에서도 콜백함수가 사용된다.



1.4 콜백함수의 주의점

자바스크립트를 처음배우고 콜백함수의 챕터에 들어가게 된다면 콜백지옥이라는 단어를 들어봤을 것이다.

콜백지옥이란 무엇일까?

먼저 콜백함수란 함수 내부에 함수가 존재하여서 먼저 실행되는걸 콜백함수라고 한다.

콜백함수를 사용해야 한다는건 우리가 해결할 수 없는 것 혹은 적어도 정해지지 않은 시점에 코드를 실행해야 하는 메커니즘을 제공해야 한다는 것이다.

하지만 콜백의 중첩이 많아지면 콜백지옥에 빠지게 된다.

const fakeRequest = (url, success, fail) => {
    const delay = Math.random();
    setTimeout(() => {
        if (delay > 0.5){
            success("complete worked");
        }else{
            fail("fail worked");
        }
    },1000);
};

fakeRequest("book.com/", (reponse) => {
    console.log(reponse);
    fakeRequest("book.com/page2", (response) => {
        console.log(response);
        fakeRequest("book.com/page3", (response) => {
            console.log(response);
        }, (response) => {
            console.log(response);
        })
    }, (response) => {
        console.log(response);
    })
}, (response)=> {
    console.log(response);
})

위 코드는 가상의 서버에다가 데이터를 요청한 것이라 생각하자

여기서 주목해야 할 점은 데이터 요청이 연속적으로 이뤄진다는 점이다.

즉, 첫번째 요청에 성공적인 응답이 돌아온다면 두번째 요청이 들어가고 또 같은 방식으로 세번째 요청이 들어가는 것이다.

위와같이 콜백함수로 연속된 요청을 처리하기엔 코드의 가독성이 떨어지고 만약 응답에 실패했을 경우 어느 부분에서 실패했는지 알기가 힘들다.

이처럼 복잡한 콜백을 사용해야 할 경우 편하게 해주는게 Promise와 비동기 함수이다.



2. 익명함수



2.1 익명함수란?

호이스팅에 의해서 메모리에 올라가는 일반함수와는 반대로 익명함수는 말 그대로 함수란 정의만 하고 해당 함수의 이름을 정의하지 않는 함수이다.

익명함수는 호이스팅이 일어나지 않고 실행할때만 메모리에 올라가는 함수이다.

그래서 보통은 일회성 함수에서 많이쓰이는 함수 형태이다.



2.2 익명함수 예시

console.log(add(1, 2));

function add(x, y) {
  return x + y;
}

위와같이 일반함수로 하면 메모리에 올라가므로 대규모 프로젝트일 경우 제한적인 자원에 한계가 오기 쉽다.


로직이 동작하는 순서를 보면 "console.log"과 위에 있지만 밑에 있던 "add"일반함수가 먼저 호이스팅에 의해 메모리에 올라가는걸 확인할 수 있다.



function multi(x, y, z, add) {
  return add(x, y) * z;
}

console.log(
  multi(1, 2, 3, (x, y) => {
    return x + y;
  })
);

위와같이 익명함수는 호이스팅이 일어나지 않으므로 메모리에 바로 올라가지 않고 해당 호출부가 실행된다면 그 때 메모리에 올라가게 된다.
즉, 메모리에 올라가는 일반함수보다 메모리에 대한 부담이 적다.

그래서 일회성인 함수에는 익명함수를 쓰는게 자원관리차원에서 장점이 있다고 할 수 있다.



profile
개발진행형

0개의 댓글