Callback (TIL 43일차)

EenSung Kim·2021년 5월 18일
1


Intro

살다보면 바빠서 전화를 못 받는 경우가 종종 생기죠. 이 때 나중에 내가 시간이 나면 부재중 전화 목록에서 전화걸었던 사람에게 다시 전화하는 걸 콜백이라고 하나보더라구요. 저는 누군가와 연락할 때 카톡을 선호하는 편이라, 콜백이라는 말을 위에 짤을 통해서 처음 알게 되었습니다.

근데 프로그래밍에서도 콜백이라는 단어를 사용합니다. 콜백 함수를 말할 때 쓰는데요. 아무래도 콜백 함수가 "비동기적" 이라는 말과 같이 사용될 때가 많기 때문에 비동기적인 것에 대해 먼저 이야기 하고 콜백 함수를 정리해보려고 합니다.


비동기적(Asynchronous)이란?

"비동기적" (Asynchronous) 이란 말은 평소에 쓸 법한 단어는 아닙니다만, 우리는 살면서 이 개념에 매우 익숙한 편입니다. 카페나 식당에서 주문하는 것도 다 비동기적인 이벤트라고 할 수 있기 때문입니다.

그래서 대체 비동기적인게 뭐냐? 빠른 이해를 돕기 위해 카페에서 주문하고 음료를 받는 과정이 만약 "동기적이라면" 어떨지 한 번 상상해보도록 하겠습니다.

카페에 주문을 하러 들어갔습니다. 줄이 길게 늘어서있네요. '이 집 맛집인가보네' 생각하셨을지도 모르겠지만 그렇지 않습니다. 이 카페는 손님에게서 주문을 받고 음료를 만들어서 전달하고 나서야 비로소 다음 손님에게 주문을 받고 있기 때문입니다. 마침 일하는 분도 한 분이라 아무리 기다려도 줄이 줄어들지를 않네요. 기다리다 못해 결국 다른 카페에 가기로 결정했습니다.

위에 굵게 처리한 부분이 바로 동기적인 실행 과정입니다. 모든 것을 순차적으로, 그리고 하나의 이벤트를 완전히 마무리 짓고서야 그 다음 작업을 하는 것을 말하죠. 프로그래밍을 배워나가면 코드의 실행 과정이 순차적으로 진행된다는 걸 알 수 있습니다. 그렇다면 비동기적이라는 개념은 갑자기 어디에서 튀어나온 것일까요?

이는 (다른 언어도 물론 마찬가지이겠습니다만) 자바스크립트가 웹 개발을 위한 언어이기 때문입니다. 만약 우리가 유튜브를 보려고 하는데, 영상이 플레이되는 동안 다른 작업을 아무 것도 할 수 없다고 생각해보세요. 카페에서 앞 사람이 주문한 음료가 나오기 전까지 내 주문을 안 받아주는 상황인 거죠. 아마 답답해서 유튜브를 더 이상 사용하지 못 할 겁니다.

하지만 우리는 유튜브 영상을 보다가도 얼마든지 더 관심이 가는 다른 영상을 틀 수도 있고, 댓글을 작성할 수도 있습니다. 이 모든 것은 웹에서 일어나는 많은 이벤트들이 비동기적으로 작동하기 때문에 가능한 것이고, 콜백 함수는 주로 이런 비동기적인 실행을 위해 사용됩니다.


콜백 함수

콜백 함수란 다른 함수의 인자로 전달되는 함수를 말합니다. 이 때 전달되는 함수를 callback , 함수를 전달받는 함수를 caller 라고 하는데요. caller 함수는 넘겨받은 callback 함수는 원하는 용도로 활용할 수 있습니다. 반복해서 활용할 수도 있고, 어떤 이벤트에 따라서 실행되게도 할 수 있죠. 하지만 오늘의 주제로 콜백함수를 잡은 것은 바로 비동기적인 상황에서 콜백함수를 활용할 수 있기 때문입니다.

비동기적으로 무언가를 처리하는 것이 조금 더 효율적인 것처럼 보인다는 건 앞서서도 설명해드렸습니다만, 때로는 비동기적으로 처리되는 것이 마음에 들지 않을 수도 있습니다.

혹시 식당에서 내가 먼저 주문을 했는데 나보다 늦게 온 사람이 먼저 음식을 받는 경험 해보신 적 있으신가요? 한두 주문이 밀리는 거야 그럴 수 있다지만 내 주문이 한참동안이나 안 나오게 되면 불쾌할 수도 있는데요.

프로그래밍에서 비동기적인 것들의 순서를 정해주고 싶을 때 바로 이 콜백 함수를 활용할 수 있습니다. 콜백 함수 안에서 다시 콜백을 호출하는 식으로 콜백을 중첩해서 사용하는 식인데요.

const doThisAfter2Sec = (string, callback) => {
  setTimeout(() => {
	console.log(string);
    callback();
  }, 2000)
}

doThisAfter2Sec('this', () => {
  doThisAfter2Sec('that', () => {
    doThisAfter2Sec('there?', () => {
      console.log('this is the end');
    })
  })
})

이렇게 진행하게 되면 'this', 'that', 'there?' 이 3 개의 문자열이 2초마다 console.log 에 찍히게 되고, 마지막 'there?' 이 출력되면서 바로 이어서 'this is the end' 도 함께 출력됩니다.

지금은 실행되는 시간을 2초로 고정해두었지만 만약 저 시간이 들쭉날쭉이라면 어떨까요? 그렇다 하더라도 콜백 함수를 중첩해서 사용하고 있기 때문에, 그 이전의 console.log 가 실행된 이후에나 callback 을 실행하게 됩니다.


Callback Hell

콜백 함수를 중첩해서 쌓다 보면 코드의 범위를 확인하는 것이 매우 어려워지는 사태를 초래하게 됩니다. 이를 Callback Hell 이라고 하는데요. 위의 코드에서도 발견할 수 있지만 조금 더 극단적인 형태를 만들어보도록 하겠습니다.

doThisAfter2Sec('this', () => {
  doThisAfter2Sec('that', () => {
    doThisAfter2Sec('there?', () => {
      doThisAfter2Sec('what?', () => {
        doThisAfter2Sec('hey', () => {
       	  doThisAfter2Sec('stop', () => {
      	    doThisAfter2Sec('what is going on', () => {
      	      doThisAfter2Sec('no God please nooooo', () => {
      
              })
            })
          })
        })
      })
    })
  })
})

언뜻 봐도 아주 끔찍한 코드가 되었죠. 오늘의 나는 어제의 내가 작성한 코드를 알아보지 못하기 때문에, 나중에 코드를 들여다봐야 한다면 뭐가 뭔지 알기가 어려울 겁니다. 만약 여러 사람이 협업해야 한다면 말할 것도 없겠죠. 일의 진행속도는 더뎌지고, 아무도 건드리지 못하는 코드가 되어 전체를 망가뜨릴 수 있습니다.

이런 콜백 헬을 벗어나기 위해 우리가 알아야 하는 것이 바로 Promise 와 Async, Await 입니다. 이 부분은 다음에 또 다뤄보도록 하겠습니다.

profile
iOS 개발자로 전직하기 위해 공부 중입니다.

2개의 댓글

comment-user-thumbnail
2021년 5월 30일

안녕하세요 은성님 29기 동기 수강생입니다 ! 정리해두신 내용 너무 좋네요
잘 배우고 갑니다 :) bb

1개의 답글