JavaScript 비동기 처리 [1] - 비동기 처리란, Callback

최원빈·2022년 10월 17일
0

다음 주에 강의할 주제는 <비동기처리>이다.
원래는 주마다 하는 강의지만, 시험 & 실습 등 여러가지가 겹쳐 2주의 휴식(겸 공부하는)기간을 주게 되었는데,
다들 실습수업은 밀리고 중간고사는 취소되어서 괜히 미룬게 아닌가 싶었지만, 주제가 주제이니만큼 나쁘진 않다고 생각한다.

비동기처리, Callback, Promise, async + await이 전부 이번 강의의 주제인데, 3주로 늘어난 만큼 더욱 완벽한 강의를 위해 강의할 내용을 정리해보려 한다.
그만큼 처음 듣기엔 어려운 내용이기도 하니깐.

1년 전에는 MDN을, 이번 강의 자료를 조사하면서 모던 자바스크립트 튜토리얼 또한 참고했다. 그리고 Web API와 작업 큐에 대해 쉽게 설명되어있는 문서를 참고했다.

0. 비동기란?

한 코드를 실행하는것이 다음 코드의 실행을 멈추지 않는다는 점.
동기적이지 않은, 요청에 대한 결과를 기다리지 않는 방식.

역시 가장 많이 나오는 예제는 window.setTimeout() 함수를 통한 예제이다.
JS 기초 공부를 하다보면 setTimeout() 함수를 접할 일이 많은데, 우선 이 함수를 통해 비동기의 대한 이해를 확실하게 하고 가야 한다.

console.log("first");

window.setTimeout(() => {
  console.log("second")
}, 1000)

console.log("third")

콘솔창엔 first와 third가 나오고, 1초 뒤에 second가 입력될 것이다.

근데 여기서 JS공부를 했던, 혹은 주워들은 경험이 있는 사람들이라면 자바스크립트는 Single-Thread 언어란 점을 걸고 질문을 할 수 있다.

"자바스크립트는 싱글쓰레드 언어인데 왜 쓰레드를 따라 setTimeout() 함수를 기다리지 않고 third를 출력하나요?"

0-1. Web API - 브라우저에 전달

자바스크립트가 싱글쓰레드라는 뜻은 쉽게 말하자면 코드를 한 줄로 쭉 읽어 내려간다는 뜻이다.
함수 등으로 인한 분기점이 일어나면 두 갈래로 나뉘어져 코드를 실행하는 것이 아닌, 한 줄기를 이어 나간다는 뜻이다.

그렇다면 앞에서 말한 window.setTimeout() 에서, 그 내부의 함수를 실행할 때까지 한 줄기로 기다리지 않고 다음 함수로 넘어간다는 말과 모순이 생긴다.

이것이 가능한 이유가 Web API 덕분이다. window.setTimeout()함수를 호출함과 동시에 이를 위임한다.
setTimeout과 같은 비동기적 코드를 만났을 때 JS는 나머지 코드를 이어서 실행하면서, 브라우저에서 실행한 경우 위임받은 함수를 Web ApI를 통해 처리하고 있게 만들어 싱글쓰레드지만 멀티쓰레드처럼 동작하는 것이 가능한 것이다.
이렇게 자바스크립트 엔진은 비동기적 처리가 가능하도록 설계되어있다.

만약 싱글쓰레드 그 자체로 동기적 처리만 가능하다면 성능이 얼마나 떨어졌을지를 생각해보자.
커다란 프로젝트에서 setTimeout 한번 쓰면 그거 지나는동안 다른 모든 코드가 멈추는거다. 싱글쓰레드니깐.
이를 해결하기 위해서 비동기적으로 처리할 수 있게 자바스크립트 엔진은 Web API를 두었고, 이를 우리가 활용해야 한다.

여기까지 기초 내용이다.
싱글쓰레드인 자바스크립트의 동작 방식이 이해됐다면, 이제 비동기적 처리가 뭔지부터 알아보자.

1. 비동기 처리?

자바스크립트는 한 코드의 실행 동안 나머지 코드의 실행을 멈추지 않는다고 했다.
그렇다면 멈출 필요가 있는 코드라면 어떨까?

서버를 통해 값을 받아오는 대부분의 경우가 그러하다.
나는 axios를 많이 이용해왔으니, axios를 예로 들어보자.

let response;
response = axios.get("https://api.thecatapi.com/v1/images/search?size=full");

console.log("Cat Image Url is " + response); // Cat Image Url is <Promise>...

귀여운 고양이의 랜덤한 사진의 url을 전달해주는 api를 사용했다. response가 왜 이상한 값이 나올까?

앞에서 말한 자바스크립트의 처리 방식을 생각하자.
axios.get()이 선언됨과 동시에 이는 기다려야 하는 일이므로 브라우저(Web API)에게 넘긴다.

아까도 말했듯이 싱글쓰레드인 자바스크립트가 큰 프로젝트에서 저 axios.get을 전부 기다리고 뒤 코드를 진행하지 않는다면 엄청난 성능의 문제가 생길 것이다. 그래서 기다리지도 않고 브라우저에게 위임하는 것이고.
그렇기에 우리는 저 axios.get()을 비동기 처리할 필요가 생긴다.

비동기 처리의 이유가 이해됐다면 그 방법을 알아보자.

2. Callback

콜백 자체의 정의는 단순하다.

콜백 함수란 함수의 인자로 함수를 넣는 함수를 말한다.

이를 통해 함수를 특정한 시점에 호출할 수 있다.

function waitFiveSec(callback) {
  setTimeout(() => {
    callback();
  }, 5000)
}

function doSomething() {
  console.log("Doing!");
}

waitFiveSec(doSomething);

그냥 Doing!을 콘솔에 찍는 함수지만, 5초를 기다린 뒤에 함수를 실행시키기 위해 이런 방식으로 콜백함수를 사용해 비동기 처리를 할 수 있다.

서버와의 통신을 필요로 하는 코드를 보자. $는 JS를 통한 비동기 통신을 돕는 라이브러리 내장 함수로, 통신 이후, 그 결과에 따라 콜백함수를 실행시킨다.

function callbackAfterGet(callback){
  $.get('https://domain/api/url',(res) => {
    callback(res);
  });
}

get메소드의 두번째 인자로 함수를 담았고, 값을 받아온 뒤에 만들어둔 callback함수를 실행하는, 두 번의 콜백을 포함시킨 구조이다.

이처럼 비동기 처리를 지원하는 통신 라이브러리 중에서는, 콜백을 활용해 쉽게 비동기 처리를 해결하는 라이브러리도 있다.

2-1. Callback Hell, 콜백 지옥

비동기 처리 한번으로 끝나면 괜찮겠지만, 비동기 처리가 끝난 데이터를 가지고 또 비동기 통신을 해야하고, 그 데이터를 활용해 또 비동기 처리가 필요해진다면?

콜백으로 해결하려면 함수 내에 함수가 반복적으로 들어가면서 처리하기 힘든 코드가 된다.
구글에 가서 Callback Hell이라고 검색하고 이미지에 들어가보자.

코드가 점점 오른쪽으로 쏠려가며 감당할 수 없게 된다.
하지만 내가 원하는 코드만 있을 수 는 없는 법. 반복적인 비동기 처리를 위해 콜백 지옥을 만들지 않고 비동기 처리를 할 수 있는 방법이 몇가지 있다.

그 방법인 Promise와 async + await은 내용이 길어져서 다음 포스팅에 이어서 해야겠다.

profile
FrontEnd Developer

0개의 댓글