BE/Javascriptㅤ|ㅤTypescript

[JS] 자바스크립트에서의 Callback (콜백함수) 이해해보기.

Bans 2022. 7. 6. 01:27

Javascript 를 사용하면서, (or 다른 언어에서 이벤트 등의 특정 상황에서)

특정한 이벤트에 실행시키는 함수를 실행할 때 (사실 JS 외에는 실제로 만나보지 못했다.. 화살표함수 이녀석)

 

우리는 Callback 이라는 개념과 마주하게 된다.

 

우선 콜백의 정의부터 알아보자.

'콜백(Callback)의 정의' 라고 검색했을 때

맨 처음 나오는 위키백과의 정의는 아래와 같이 시작한다.

 

프로그래밍에서 콜백(callback) 또는 콜애프터 함수(call-after function)[1]는 다른 코드의 인수로서 넘겨주는 실행 가능한 코드를 말한다. 콜백을 넘겨받는 코드는 이 콜백을 필요에 따라 즉시 실행할 수도 있고, 아니면 나중에 실행할 수도 있다.

 

Javascript 는 탄생 배경에서부터 웹 브라우저를 위해 만들어진 언어이다.

네트워크 통신을 통해 클라이언트에게 정보를 전달하기에, 네트워크를 사용하지 않고 연산하는 기기들에 비해

연산하는데 '비교적' 시간이 추가적으로 더 필요하고,

문서가 담고있는 정보의 양과 연산해야하는 정보가 많아진다면 (사진, 동영상, 데이터 등등..)

문서 전체를 로드하는데에 필요한 시간은 '물리적으로' 더 늘어나게 될 것이다.

 

하지만 웹 브라우져를 사용하는 클라이언트의 특징이 무엇인가

(라고 쓰고 당신은 과연 로딩을 몇초나 기다리는가.. 라고 읽는다)

 

얼마나 더 기다려야 사진이 뜰까요?

 

자바스크립트는 탄생배경과 그 특징에 알맞게 싱글스레드 이며, 그러기에 한 가지의 동작이 실행되는 도중

다른 동작을 동시에 실행하기가 어렵다.

통신 중 어떤 함수의 일 처리가 길어지면, 웹 브라우저는 계속 멈춤 상태가 되고 기다려야 되며,

이러한 상황을 방지하기 위해 자바스크립트는 비동기 방식을 가지게 된다.

 

 

참고 : 싱글스레드이기에 비동기를 이용하는 자바스크립트 https://helloinyong.tistory.com/92
 

[2019.04.26] 자바스크립트의 비동기 특징과 비동기 방식을 다루는 법

자바스크립트는 싱글 스레드이다. 그래서 비동기 방식의 함수를 정말 많이 내장하고 있다. # 비동기 방식의 특징 동기적 함수들은 절대 비동기 함수를 기다려주지 않는다. 그래서 비동기 방식의

helloinyong.tistory.com

 

 

비동기 방식인 자바스크립트에서 마주하게되는

여러가지 한계를 해결하기 위해서는 어떤 방법을 이용할까?

우선 주제에 맞게 Callback 함수의 방법으로 예시를 들어보자.

 

src에 있는 스크립트를 읽어오는 함수loadScript(src) 를 예시로 비동기 동작 처리가 어떻게 일어나는지 살펴보자.

 

 

함수 loadScript(src)는 <script src="…">를 동적으로 만든 후 이를 문서에 추가한다.

브라우저는 자동으로 태그에 있는 스크립트를 불러오고, 로딩이 완료되면 스크립트를 실행하게 된다.

 

loadScript(src) 사용법은 아래와 같다.

이 때 스크립트는 ‘비동기적으로’ 실행된다.

로딩은 지금 당장 시작되더라도 실행은 당연히 함수가 끝난 후에야 되기 때문이다.

따라서 loadScript(…) 아래에 있는 코드들은 스크립트 로딩이 종료되는 걸 기다리지 않는다.

 

 

자, 이 스크립트 로딩이 끝난 후

이 스크립트 안에 있는 함수를 사용해야 하는 상황을 생각해보자.

스크립트 안에 다양한 함수가 정의되어 있고, 우리는 이 함수를 사용하려 하는 상황.

 

script.js / 안에 정의되어있는 newFunction() 함수를 사용하기 위해 아래와 같이 코드를 작성해보았다.

그런데 loadScript(...)를 호출하자마자 내부 함수를 호출하면 원하는 대로 작동하지 않는다.

 

 

위의 에러는 브라우저가 스크립트를 읽어올 수 있는 시간을 충분히 확보하지 못했기 때문에 발생한다.

그런데 현재로서는 함수 loadScript에서 스크립트 로딩이 완료되었는지 알 방법이 없다.

언젠간 스크립트가 로드되고 실행도 되겠지만, 그게 언제일 지 판별할 수 있는 자체 기능은 없기 때문이다.

 

원하는 대로 스크립트 안의 함수나 변수를 사용하려면 스크립트 로딩이 끝났는지 여부를 알 수 있어야 하며,

이를 해결하기 위해

loadScript의 두 번째 인수로 스크립트 로딩이 끝난 후 실행될 함수인 콜백(callback) 함수를 추가해 보자.

 

 

새롭게 불러온 스크립트에 있는 함수를 콜백 함수 안에서 호출하면

원하는 대로 외부 스크립트 안의 함수를 사용할 수 있다.

 

이런 방식을 ‘콜백 기반(callback-based)’ 비동기 프로그래밍이라고 한다.

 

무언가를 비동기적으로 수행하는 함수는

함수 내 동작이 모두 처리된 후 실행되어야 하는 함수가 들어갈 콜백(callback)을 인수로 반드시 제공해야 한다.

위 예시에선 loadScript의 인수로 콜백을 제공해 주었는데,

이렇게 콜백을 사용한 방식은 비동기 프로그래밍의 일반적인 접근법이다.

 

참고 : 자바스크립트가 비동기 방식을 컨트롤할 때 사용되는 콜백함수 https://ko.javascript.info/callbacks
 

콜백

 

ko.javascript.info

 

위에서 loadScript가 '콜백기반 비동기 프로그래밍' 을 사용하여 비동기 프로그래밍을 보여줬었다.

그러나 스크립트가 2개인 경우, loadScript 가 두번 사용될 경우는 어떠한가?

콜백함수를 두 번 중첩해서 사용하면 해결되긴 한다.

 

하지만..

스크립트가 3개인 경우? 4개인 경우? (.... n개인 경우?)

 

 

위와같이 loadScript를 여러번 중첩해서 사용하다보면

callback 함수들은 마치 피라미드 모양으로 중첩사용되는 듯한 양상을 보이고

이러한 상황을

 

Callback Hell (콜백지옥 ) 혹은 'Pyramid of Doom(멸망의 피라미드)' 라고 부른다

 

welcome to 'Callback Hell'
welcome to 'Pyramid of Doom'

 

손 쓸 수 없는 상황까지 커져만 가는 피라미드의 문제를 해결하기 위해

 

자바스크립트는 프로미스(Promis) 와 async / await 를 사용하여 이 콜백지옥을 벗어날 수 있었다.

 

프로미스와 async / await 는 다음 기회에 이 문제를 다룰 때

또 다뤄볼 예정이다 :-)