1. 콜백 함수란?
콜백 함수는 다른 코드의 인자로 넘겨주는 함수이다. 콜백 함수를 넘겨받은 코드는 이 콜백 함수를 필요에 따라 적절한 시점에 실행할 것이다.
callback은 '부르다', '호출하다'는 의미인 call과, '되돌다'는 의미인 back의 합성어로, '되돌아 호출해 달라'는 명령이다. 즉, 어떤 함수 X를 호출하면서 '특정 조건일 때 함수 Y를 실행해서 나에게 알려달라'는 요청을 함께 보내는 것이다. 이. 요청을 받은 함수 X의 입장에서는 해당 조건이 갖춰졌는지 여부를 스스로 판단하고 Y를 직접 호출합니다.
결론적으로, 콜백 함수는 다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수이다. 콜백 함수를 위임받은 코드는 자체적인 내부 로직에 의해 이 콜백 함수를 적절한 시점에 실행할 것이다.
2. 제어권
2-1. 호출 시점
setInterval을 호출할 때 두 개의 매개변수를 전달했는데, 첫 번째는 익명 함수이고 두 번째는 300이라는 숫자이고 좀 더 확인하기 쉽게 아래 코드처럼 나타낼 수 있다.
setInterval에 전달한 첫 번째 인자인 cbFunc 함수(콜백 함수)는 0.3초마다 자동으로 실행될 것이다. 콜백 함수 내부에서는 count 값을 출력하고, count를 1만큼 증가시킨 다음, 그 값이 4보다 크면 반복 실행을 종료하라고 한다.
setInterval이라고 하는 '다른 코드'에 첫 번째 인자로서 cbFunc 함수를 넘겨주자 제어권을 넘겨받은 setInterval이 스스로의 판단에 따라 적절한 시점에(0.3초마다) 이 익명 함수를 실행한다. 이처럼 콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점에 대한 제어권을 가진다.
2-2. 인자
map 메서드는 첫 번째 인자로 callback 함수를 받고, 생략 가능한 두 번째 인자로 콜백 함수 내부에서 this로 인식할 대상을 특정할 수 있다. 그리고 메서드의 대상이 되는 배열의 모든 요소들을 처음부터 끝까지 하나씩 꺼내어 콜백 함수를 반복 호출하고, 콜백 함수의 실행 결과들을 모아 새로운 배열을 만든다.
콜백 함수의 첫 번째 인자에는 배열의 요소 중 현재값이, 두 번째 인자에는 현재값의 인덱스가, 세 번째 인자에는 map 메서드의 대상이 되는 배열 자체가 담긴다.
만약 인자 순서를 바꿀 경우, 예상치 못한 문제가 발생한다. 왜냐하면 컴퓨터는 그저 첫 번째, 두 번째의 순서에 의해서만 각각을 구분하고 인식하기 때문이다. 즉, 정의된 규칙에 따라 함수를 작성해야 한다.
이처럼 콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수를 호출할 때 인자에 어떤 값들을 어떤 순서로 넘길 것인지에 대한 제어권을 가진다.
2-3. this
콜백 함수도 함수이기 때문에 기본적으로는 this가 전역객체를 참조하지만, 제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조하게 된다.
map 메서드를 직접 구현할 경우 아래와 같은 코드를 만들 수 있다.
this에는 thisArg 값이 있을 경우에는 그 값을, 없을 경우에는 전역객체를 지정한다.
3. 콜백 함수는 함수다.
콜백 함수로 어떤 객체의 메서드를 전달하더라도 그 메서드는 메서드가 아닌 '함수'로서 호출된다.
7번째 줄에서 메서드의 이름 앞에 점이 있으니 메서드로서 호출했기 때문에, this는 obj를 가리키게 된다.
한편 8번째 줄에서는 이 메서드를 forEach 함수의 콜백 함수로서 전달했다. obj를 this로 하는 메서드를 그대로 전달한 것이 아니라, obj.logValues가 가리키는 함수만 전달한 것이다. 그래서 obj와 직접적인 연관이 없어지게 되고 별도로 this를 지정하는 인자를 지정하지 않았으므로 함수 내부에서의 this는 전역객체를 바라보게 된다.
4. 콜백 함수 내부의 this에 다른 값 바인딩하기
콜백 함수 내부에서 this가 객체를 바라보게 하고 싶다면 bind 메서드를 이용할 수 있다.
5. 콜백 지옥과 비동기 제어
5-1. 콜백 지옥이란?
콜백 지옥은 콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상으로, 자바스크립트에서 흔히 발생하는 문제이다.
주로 비동기적인 작업을 수행하기 위해 이러한 형태가 자주 등장하는데, 가독성이 떨어지고 코드를 수정하기도 어렵다.
5-2. 비동기란?
동기적인 코드는 현재 실행 중인 코드가 완료된 후에야 다음 코드를 실행하는 방식이다. 반대로 비동기적인 코드는 현재 실행 중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어간다.
즉, 별도의 요청, 실행 대기, 보류 등과 관련된 코드는 비동기적인 코드이다.
5-3. 콜백 지옥
콜백 지옥 예시는 다음과 같다.
각 콜백은 커피 이름을 전달하고 목록에 이름을 추가한다. 들여쓰기가 과도하게 깊어졌을뿐더러 값이 전달되는 순서가 '아래에서 위로' 향하고 있어 어색하게 느껴진다.
이를 해결하기 위해 콜백 함수를 모두 기명함수로 전환할 수는 있지만, ES6에서는 Promise, Generator 등이 도입되었고 ES2017에서는 async/await 가 도입되어 비동기적인 작업을 동기적으로 보이게끔 처리해 주는 장치를 만들었다.
Promise
Promise의 인자로 넘겨주는 콜백 함수는 바로 실행되지만 그 내부에 resolve 또는 reject 함수를 호출하는 구문이 있을 경우 둘 중 하나가 실행되기 전가지 다음(then) 또는 오류 구문(catch)으로 넘어가지 않는다. 따라서 비동기 작업이 완료될 때 비로소 resolve 또는 reject를 호출하는 방법으로 비동기 작업의 동기적 표현이 가능하다.
Promise(1) 코드의 반복적인 내용을 함수화하여 클로저를 활용하여 표현할 수도 있다.
6번째 줄의 '*'이 붙은 함수가 바로 Generator 함수이다. 이를 실행하면 Interator가 반환되는데, Interator는 next라는 메서드를 가지고 있다. 이 next 메서드를 호출하면 Generator 함수 내부에서 가장 먼저 등장하는 yield에서 함수의 실행을 멈춘다. 이후 다시 next 메서드를 호출하면 앞서 멈췄던 부분부터 시작해서 그다음에 등장하는 yield에서 함수의 실행을 멈춘다.
함수 앞에 async를 표기하고, 함수 내부에서 실질적인 비동기 작업이 필요한 위치마다 await를 표기하는 것만으로 뒤의 내용을 Promise로 자동 전환하고, 해당 내용이 resolve 된 이후에야 다음으로 진행된다. 즉, Promise의 then과 흡사한 효과를 얻을 수 있다.
6. 정리
콜백 함수는 다른 코드에 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수이다.
제어권을 넘겨받은 코드는 아래와 같은 제어권을 가진다.
- 콜백 함수를 호출하는 시점을 스스로 판단해서 실행한다.
- 콜백 함수를 호출할 때 인자로 넘겨줄 값들 및 그 순서가 정해져 있다.
- 콜백 함수의 this는 정하지 않은 경우에는 전역객체를 바라보고, 사용자 임의로 바꾸고 싶은 경우 bind 메서드를 활용하면 된다.
- 어떤 함수에 인자로 메서드를 전달하더라도 이는 결국 함수로서 실행된다.
- 비동기 제어를 위해 콜백 함수를 사용하다 보면 콜백 지옥에 빠지게 되는데, Promise, Generator, async/await 등으로 콜백 지옥에 벗어날 수 있다.
'💜 프론트엔드 > JavaScript' 카테고리의 다른 글
[코어자바스크립트] 03. this (0) | 2025.01.15 |
---|---|
[코어자바스크립트] 02. 실행 컨텍스트 (1) | 2025.01.11 |
[코어자바스크립트] 01. 데이터 타입 (1) | 2024.12.23 |
[JavaScript] 이벤트 버블링, 캡쳐링, 위임 & HTTP 메소드 (0) | 2024.04.07 |
[JavaScript] var, let, const 중복 선언 허용, 스코프, 호이스팅 (0) | 2024.03.31 |
FE 개발자가 되고 싶은 짱잼이
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!