Yeon's 개발블로그

지식을 전파하는 개발자가 되고싶습니다.

JS

[JS] 콜백함수, 콜백지옥

Dev.yeon 2022. 5. 13. 16:03

1.  콜백함수란? 

다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수이다. 예를들면 A와 B는 토요일 오전 7시에 만나기로 하였다. 둘은 만나기위해 5시에 기상하여야 한다. A는 알람을 5시에 맞춰 푹자다가 기상하였다. 하지만 B는 알람이 고장나서 편히 잠들지 못하고 수시로 일어나서 시간을 확인하다가 기상하였다. 여기서 콜백함수를 쓴 사람은 A이다. B는 수시로 시간을 구하는 함수를 직접 호출하였지만 A는 알람을 울리는 함수를 호출할 당시에는 아무것도 하지 않다가 정해진 시간이 되었을때 함수를 호출하였다. B는 함수를 호출하는 제어권을 자신이 가지고 있으면서 함수를 호출하였고, A는 제어권을 알람에게 넘겨주고 취침이라는 다른일을 하다가 함수가 호출되었다.

여기서 콜백함수의 중요한 키워드는 제어권이다. 콜백함수는 다른 코드에게 인자와 제어권을 함께 넘겨주게 된다. 콜백함수를 위임받은 코드는 자체적인 내부로직에 의해 이 콜백함수를 적절한 시점에 실행한다. 제어권을 넘겨받은 코드는 (1)호출하는 시점 (2) 인자의 순서 (3)this 지정에 대한 제어권을 획득한다. 

1) 호출하는 시점: setInterval이라고 하는 '다른 코드'에 첫번째 인자로 ex1func 함수를 넘겨주자 제어권을 넘겨받은 setInterval이 스스로 판단에 따라 적절한 시점(0.3)에 익명함수를 실행했다. 따라서 콜백함수의 제어권을 넘겨받은 코드는 콜백함수 호출시점에 대한 제어권을 가진다.

호출시점에 대한 제어권

2) 인자의 순서: 밑의 예시를 보면 첫번째 예시에서는 첫번째 인덱스 0 에 대한 콜백함수는 currnetValue에는 10, index에는 0이 담기고 15를 반환한다. 두번째 인덱스 1에 대한 콜백함수는 currentValue에는 20, index에는 1이 담기고 25를 반환한다. 두번째 예시에서 컴퓨터는 순서에 의해서만 각각을 구분하고 인식한다. map 메서드에 정의된 규칙에 따라 함수를 작성해야하며, map메서드에는 콜백함수를 호출할 때 인자의 순서에 대한 정보가 들어있다. 따라서 콜백함수의 제어권을 넘겨받은 코드는 콜백함수를 호출할 때 인자에 어떤값들을 어떤 순서로 넘길 것인지에 대한 제어권을 가진다.

인자의 순서에 대한 제어권

3) this 지정: 밑의 예시에서 마지막인자에 담긴 userData는 call함수의 첫번째 인자로 넘어가게 되어서 this객체가 매핑된다. 콜백함수도 함수이기 때문에 기본적으로 this가 전역객체를 참조하지만, 제어권을 넘겨받을 코드에서 콜백함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조하게 된다. 따라서 call/ apply 함수를 이용하여 첫번째 인자에 콜백함수 내부에서의 this가 될 대상을 명시적으로 바인딩해야한다.

this 지정에 대한 제어권

 

2. 콜백지옥이란? 

 콜백함수를 익명함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들정도로 깊어지는 현상을 말한다. 현대의 자바스크립트는 웹의 복잡도가 높아진 만큼 비동기적인 코드의 비중이 예전보다 훨씬 높아진 상횡이며, 비동기적인 코드는 별도의 요청, 실행 대기, 보류 등으로 콜백지옥에 빠지기 훨씬 쉽다.

 

콜백지옥 예시

해결방법 1) 기명함수로 전환: 기명함수로의 변환은 코드의 가독성을 높인다는 장점이 있지만, 일회성 함수를 전부 변수에 할당해야 하는 것이 반복되고 복잡하여 좋은 방법은 아니다. 

기명함수로 전환

해결방법 2) promise 사용: ES6에 등장한 promise를 사용할 수도 있다. new연산자와 함께 호출한 promise의 인자로 넘겨주는 콜백함수는 호출할때 바로 실행되지만 그 내부에 resolve 또는 rejected 함수를 호출하는 구문이 있을 경우 둘 중 하나가 실행되기 전까지는 다음으로 넘어가지 않는다.

promise 사용

해결방법 3) promise + async/await: ES2017에는 가독성이 뛰어나면서도 작성법이 간단한 async/await 기능이 추가되었다. 비동기작업을 하고자하는 함수앞에 async를 표시하고 함수 내부에서 실질적으로 비동기 작업이 필요한 위치마다 await를 표기하면 자동적으로 await 뒤의 내용을 promise로 전환하고 해당내용이 resolve된 이후에야 다음으로 진행한다. promise then과 같은 원리이다.

promise + async/await

 

✨ 이 글은 정재남님의 코어자바스크립트를 참고하여 작성된 글입니다. 프론트엔드 개발자라면 꼭 사서 읽어보시는 것을 추천드립니다.

 

'JS' 카테고리의 다른 글

[JS] This, Binding  (0) 2022.05.12
[JS] 실행컨텍스트, 호이스팅, 스코프체인  (0) 2022.05.11
[JS] 자바스크립트 데이터 타입  (0) 2022.05.11
[JS] 클로저 개념  (2) 2020.11.26