자바스크립트 동기와 비동기 2 - 콜백 함수(Callback function)

RN·2024년 6월 18일

자바스크립트

목록 보기
3/11

이전 포스트에서 콜백 함수에 대해 이야기할 때 비동기 프로그래밍에서의 콜백 함수라고 이야기했다.

나는 콜백 함수를 동기와 비동기를 배우면서 같이 배웠다.

그때 비동기를 설명할 때 콜백 함수를 배우게 되었고, 당시에는 콜백 함수를 비동기 함수들에만 사용했기에 이 콜백 함수가 비동기에만 사용되는 거라고 착각하였다.

심지어는 공부를 더 하면서 콜백을 비동기가 아닌 곳에도 사용하면서도 무의식적으로 콜백은 비동기에... 라는 생각을 가지고 있었다.

하지만 콜백 함수를 대체 왜 사용해야 하는지가 갑자기 궁금해졌고, 이에 대해 찾아보면서 콜백에 대해 더 깊게 이해할 수 있었다.

역시 무언가를 이해할때는 왜? 라는 질문이 최고인거 같다. 물론 여기에 실습도 포함해야겠지만

1. 콜백 함수(Callback function)


1.1 콜백 함수 사용하는 법

콜백 함수의 기본 형태는 이렇다.

함수의 인자로 함수를 전달하는 데 자바스크립트는 함수의 인자로 객체를 전달할 수 있다.

이전 포스트인 원시타입 vs 객체타입에서 함수 역시 객체라고 했다.

그러니 우리는 함수를 함수의 인자로 전달할 수 있게 되었다!!


위의 콜백 함수 사용방식을 다른 방식으로 바꿀 수 있다.

그냥함수()를 호출할 때 함수를 정의하면서 전달할 수 있다. 화살표 함수로도 마찬가지다.

눈치 챈 사람은 눈치챘겠지만 setTimeout을 사용할 때랑 같다.

결과는 셋 다 아래와 같다.




1.2 비동기에서 콜백 함수를 사용하는 이유


사실 이전 포스트 2-1 에서 콜백 함수를 사용하는 이유에 대해 이야기를 했지만 한 번 더 알아보자.

이전 포스트 2-1 에서는 우리가 우리가 비동기 프로그래밍에서 콜백 함수를 사용하는 이유에 대해서 알아보았다.

우리는 비동기 작업 후에 반드시 실행시켜야 하는 코드가 있다.
다시 말해 비동기 작업 -> 반드시 실행시켜야 하는 코드 라는 순서로 중간에 어떤 코드도 끼어들지 않고 동기적으로 동작하도록 해야한다.
즉, 비동기 프로그래밍에서 콜백 함수는 비동기 작업이 순차적으로 동작해야할 때 사용할 수 있다

위의 코드는 랜덤으로 웹툰을 골라서 해당 페이지를 열어주는 함수다.

물론 코드를 보기 편하게 하기위해 랜덤 웹툰은 아니고 신의 탑이라는 웹툰이 전달되도록 만들었다.

웹툰랜덤으로보여줘() 라는 함수는 당연히 서버에 존재하는 웹툰들 중 랜덤으로 가져올 것이므로 서버에 요청과 응답을 받아야하고 어느 정도 시간이 걸릴 것이므로 비동기로 동작해야한다는 것을 알 수 있다.


그래서 이 함수에 데이터를 받아온 후 성공, 실패 여부에 따라 실행시킬 콜백 함수 두 개를 전달한다.

이 함수는 무조건 데이터가 "신의 탑" 으로 전달받도록 했기에 성공() 을 출력한다.

data = "신의 탑" 부분을 주석처리 하여 데이터를 받아오지 않도록 해보면 아래와 같이 된다.

위에서 말한 콜백 함수의 사용 이유와 이 코드를 합해 본다면

웹툰랜덤으로보여줘 라는 비동기 작업에서 반드시 동기(순서대로)로 작업해야 하는
데이터 받아온 후 -> 성공 혹은 실패여부에 따른 함수 실행
위해 우리는 콜백 함수를 사용해야 했다.




1.3 콜백 함수를 인자로 받는 비동기 API


자바스크립트 실행(런타임) 환경에서는 여러가지 Web APIs 를 제공한다.

DOM API, setTimeout, fetch, event listener 등이 있다.

Web APIs 의 대부분은 비동기로 동작한다.

이 중 가장 대표적인 setTimeout을 가지고 우리가 만든 커스텀 api가 아니라 고수들이 직접 만든 api 에서도 내가 이해한 콜백 함수의 사용 이유가 맞는지 확인해보자.

setTimeout 도 맨 윗줄의 주석처럼 콜백 함수를 인자로 받는다.

그렇기 때문에 위에서 정의한 것처럼 화살표함수를 사용해도 되고, 이름없는 함수를 사용해도 되고, 미리 정의된 함수를 전달해도 된다.


어쨌든 setTimeout의 동작순서를 보자.

  1. setTimeout은 타이머 객체를 생성한다. 이 객체는 전달받은 delay 만큼 시간을 보낸다.
  2. 타이머가 delay 만큼의 시간을 보내는 일을 전부 끝마쳤다.
  3. 비동기 작업이 끝났으니 비동기 작업이 끝난 후 반드시 실행해야 할, 우리가 전달한 콜백 함수를 실행한다.

여기서 알 수 있는 점은 코딩 천재들이 만든 setTimeout의 용도는

" 우리가 비동기로 전달받은 delay 만큼 시간을 보내는 함수를 만들테니까 너는 이 타이머 일이 끝난 후 실행시키고 싶은 함수를 콜백 함수로 전달해라. " 라는 것을 알 수 있었다.


결국 내가 이해한 대로 비동기 작업이지만 동기처럼

delay 만큼의 시간을 보낸다 -> 전달받은 콜백 함수를 실행한다.

이 순서를 반드시 지키는 것을 수행하여 이해한 부분이 틀리지 않았다는 걸 알 수 있었다.




1.4 추상화를 위한 콜백 함수?


우리가 이전 포스트에서 사용한 햄버거 주문 코드를 가져와보자.

사실 콜백 함수를 공부할 때 추가로 궁금했던 점이 있다.

분명 위의 코드에서 콜백으로 햄버거가져가라 함수를 햄버거조리 함수가 인자로 받아서 부른다.

하지만 햄버거가져가라 함수를 인자로 받아오지 않고 그냥 호출해도 되지 않나?

맞다. 사실 실행 결과는 동일하다.

그런데 만약 햄버거가져가라 함수가 아닌 다른 함수를 사용해야 한다면
우리는 햄버거조리 코드 내부에 들어가서 직접 수정해야 한다.


예를 들어 " 햄버거가져가라 " 함수가 아니라 " 햄버거포장 " 이라는 함수를 사용하려 한다면

setTimeout(() => {
	console.log(버거, "조리 완료...")
	햄버거포장(버거)
}, randomInt * 1000)

이라고 직접 햄버거조리 함수를 수정해야 한다.


하지만 저렇게 콜백 함수로 받아놓으면 햄버거가져가라 코드를 버리고 다른 코드를 사용해도 햄버거조리 함수의 내부를 수정할 필요가 없다.


이러한 사용법은 비단 비동기 프로그래밍이 아니라 동기 프로그래밍에서도 충분히 사용할 수 있는 콜백 함수의 사용 방법이다.




2. 콜백 함수의 단점


2-1. 콜백 지옥(Callback Hell)


콜백 함수로 비동기 함수를 부르고 그 비동기 함수에 또 콜백 함수가 있어서 콜백 함수를 사용하게 된다면 여러 개의 콜백 함수가 중첩되어 콜백 지옥이 발생하게 된다.


위에서 하는 말. 뭔 소린지 모르겠다. 왜 지옥이라고 불리는지 예시로 보자

햄버거만들기 함수가 성공하게 되면 똑같이 비동기 함수인 햄버거포장 함수가 호출되도록 만들었다.

그리고 그 햄버거포장 함수에도 성공, 실패 콜백함수를 받도록 되어있어 추가로 성공, 실패 함수를 정의 해줘야한다.

보기만해도 토가 나오고 어지럽다. 심지어 고작 콜백 함수 2개가 중첩되어 있을 뿐이다...

만약 4~5개 이상의 콜백이 중첩된다면 나는 이 분야에 대한 공부를 포기했을 지도 모른다.


코드를 이해할 필요는 없다. 단순히 왜 지옥이라 불리는지 보여주기 위한 코드이다.

참고로 아래는 실행 성공 결과이다.

아래는 햄버거만들기 함수 첫 번째 인자에 null 을 줘서 나온 실패 결과이다.

이러한 콜백 지옥이라는 큰 단점으로 인해서 자바스크립트는 프로미스(Promise)를 지원한다.

이 프로미스를 이용하면 저 콜백지옥의 가독성을 더 높여줘 지옥에서 벗어날 수 있게 해준다!

그렇다면 다음 포스트인 프로미스를 통해서 저 지옥에서 벗어나보도록 하자.




0개의 댓글