
자바스크립트는 기본적으로 동기(Synchronous)적으로 동작한다.
..... 동기가 뭐야? 사전적 의미로는 이랬다.
동기 (同期)
1. 같은 시기. 또는 같은 기간.
같은 시기라니;; 같은 시기라는 말과 코드를 짜는 것에 연관성을 못찾겠다. 무슨 이런 멍멍이 소리도 없다.
조금 더 찾아보니 이렇게 이해할 수 있게 되었다.
자바스크립트에서 동기적으로 동작한다는 것은 요청과 결과가 동시에(같은 시기) 발생해야 한다는 뜻이다.
이렇게 말해도 이해가 안간다. 동시에 발생한다? 여전히 이해가 안가;;
아래의 코드를 보자.

위는 a, b를 출력 후 for문을 전부 돌게된다면 c와 d를 출력한다.

위의 사진을 보면 a, b를 출력하고 잠시 멈췄다가 c, d를 출력하는 것을 알 수 있다.
즉,
아~ 이 코드를 바탕으로 위에서 말한 요청과 결과가 같은 시기에 발생한다는 것을 이해할 수 있었다.
요청 : (0부터 4999999999까지 반복하는 for문)
결과 : (for문의 종료. break가 없으니 결과는 for문이 종료되는 순간 반환할테니까)
즉, 만약 console.log('c') 가 중간에 끼어들면
for문 요청 -> console.log('c') -> for문 결과 로 같은 시기에 존재하지 않게된다.
결국 쉽게 말하자면 동기로 동작한다는 것은 코드를 위에서 아래로 순차적으로 실행한다는 것이다. 동작하는 사이에 무언가가 끼어들어선 안된다.
하지만 위에서 보다시피 동기적으로만 일을 처리하면 불필요한 리소스낭비가 발생한다.
for문이 다 돌때까지 c와 d는 기다릴 수 밖에 없으니까.
이것을 해결하기 위하여 자바스크립트는 비동기(Asynchronous)를 지원한다고 한다.
비동기(Asynchronous)는 지금 실행중인 작업을 완료할때까지 다른 작업을 멈추는 것이 아니라, 기다리지 않고 다음 명령을 수행하는 것이다.
라고 블로그들을 찾아보면 나온다. 하지만 이 설명은 처음 비동기에 대해 공부할 때는 쉽게 와닿았다가 깊게 들어갈수록 다시 와닿지 않게 되었다.
나보다 뛰어난 실력자들이 말하는 것이므로 이 말은 절대 틀린말은 아니겠지만 나는 단순히 이 설명만을 가지고는 비동기를 깊게 이해할 수 없었다.
하지만 위에서 말한 동기의 뜻을 가지고 다시 생각해보았다.
왜 이름을 비동기로 지었을까? 비동기로 지은 의미가 있을까 싶어 동기를 이해했을 때 처럼 한자를 다시 풀어보았다.
아래는 위에서 말한 동기의 뜻이었다.
자바스크립트에서 동기적으로 동작한다는 것은 요청과 결과가 동시에(같은 시기) 발생해야 한다는 뜻이다.
그렇다면 이것의 반대가 비동기일 것이다.
자바스크립트에서 비동기적으로 동작한다는 것은 요청과 결과가 동시에 발생하지 않는다는 것이다.
여기서 나는 비동기가 단순히 오래 걸리는 작업을 멈추고 다음 코드를 실행한다 라는 것이 아니라고 이해할 수 있었다.
즉, 단순히 오래 걸리는 명령을 뒤로 한 채 다음 명령을 수행하는 것에서 끝나는 게 아니라, 아예 요청과 결과가 동시에 발생하지 않아 언제 결과가 반환되는지 예측할 수 없다는 것이다.
이 개념은 콜백 함수를 배울 때 왜 콜백 함수를 사용해야 하는지를 쉽게 이해하게 만들어 주기도 했다.
실생활의 예시로 한 번 살펴보자.
첫 번째로 동기에 간한 예시이다.
- 버거킹에서 첫 번째 손님이 콰트로치즈 버거(맛있겠다)를 주문했다(function order(menu)).
- 버거킹에서 콰트로치즈 버거를 만든다(function makeBurger(menu)).
- 동기(synchronous)이기 때문에 버거를 만드는(makeBurger()) 과정이 끝날 때 까지 다음 손님은 주문을 받을 수 없다.
- 버거를 완성해서 다음 손님의 주문을 받는다. (function order(menu))
함수는 order() -> makeBurger() -> order() 순서로 동작한다.
동기이기 때문에 버거를 만들기 시작하면 버거가 완성되기 전까지 다음 손님의 주문을 받을 수 없다...
이번에는 비동기의 예시를 보자.
- 버거킹에서 첫 번째 손님이 블랙바비큐 와퍼(와...)를 주문했다(function order(menu)).
- 버거킹에서 블랙바비큐 와퍼를 제작하기 시작했다.(function makeBurger(menu)).
- 그런데 언제 블랙바비큐 와퍼가 완성될지 예측할 수가 없어서 다음 손님의 주문을 먼저 받아야겠다 ㅠㅠ...
- 다음 손님의 주문을 받는다. (function order(menu))
- 버거가 완성됐다고 첫 번째 손님에게 알린다. (return function makeBurger(menu)).
함수의 실행순서는 order() -> makeBurger() -> order()로 동일하지만
makeBurger 가 비동기로 동작하여 결과를 받기 전에 두 번째 order()를 실행하고 결과값(햄버거)은 나중에 받았다.
즉, makeBurger -> order -> return makeBurger 순서로 makeBurger는 요청과 결과 사이에 order가 끼어들어 동시에 발생하지 않았다.
다시 위에서 말한 비동기의 뜻을 가져와보자.
자바스크립트에서 비동기적으로 동작한다는 것은 요청과 결과가 동시에 발생하지 않는다는 것이다.
이제야 비동기가 무엇인지 이해가 간다.
대표적인 비동기의 예시로 브라우저에서 제공하는 Web API 인 setTimeout 함수가 있다.

위의 코드는 동기적으로 실행한다고 생각했을 때 a, b, c, d, e를 순서대로 출력한다고 생각할 수 있다.
하지만 setTimeout은 전달해준 시간만큼 전달해준 함수를 늦게 실행한다.
이 코드에서는 2000ms 즉, 2초를 전달해줬기에 2초후에 setTimeout에 전달한 함수
()=>{
console.log)('c')
}
를 실행한다.

그래서 위처럼 a,b,c,d 가 먼저 출력되고 2초 후에 c가 출력되는 것을 볼 수 있다.
※ 참고로 비동기 != 멀티스레딩 이다. 나는 처음에 비동기에 대해 학습할 때 비동기의 예시인 setTimeout()을 보고 아, 비동기는 멀티스레딩으로 동작하는 것과 같은 뜻이구나. 라고 생각하면서 학습했다가 여러가지로 헷갈리는 부분이 많아서 고생했던 기억이 난다.
비동기와 멀티스레드에 대해서는 다음 포스팅에서 다룬다.
나는 여기서 궁금한 점이 생겼다.
자바스크립트는 기본적으로 동기적으로 동작한다면서. 그럼 어떻게 비동기로 동작하게 하는데?
이제 동기적으로 동작하는 자바스크립트 코드로 비동기 프로그래밍을 할 수 있도록 도와주는 콜백 함수, 프로미스, async/await 에 대해서 배워보자.
콜백 함수에 먼저 들어가기 전에 비동기 프로그래밍에서 왜 콜백 함수를 사용하는가?
( 여기서 비동기 프로그래밍이라는 말에 주목하자. 콜백 함수는 비동기가 아닌 경우에도 사용하는 하나의 코딩 방식일 뿐이다. 콜백은 무조건 비동기에만 사용하는 것이 아니다!! )
항상 새로운 걸 배우면 대체 얘를 왜 사용해야 하는거지? 라는 궁금증이 딸려오고 그 궁금증이 해결되지 않으면 막상 자유롭게 사용하기가 힘들어진다 ㅠㅠ
위에서 말한 비동기의 뜻에 대해서 다시 알아보자
자바스크립트에서 비동기적으로 동작한다는 것은 요청과 결과가 동시에 발생하지 않는다는 것이다.
그리고 우리는 다음으로 이 멘트에 대해 이야기했다.
요청과 결과가 동시에 발생하지 않아 언제 결과가 반환되는지 예측할 수 없다는 것
이 개념들을 가지고 아래의 코드를 보자.

위의 코드는 햄버거를 주문하고 받아서 먹는 일련의 과정을 코드화 했다.
햄버거 주문을 받고 햄버거가 randomInt 초동안 조리가 되면 햄버거를 가져가라고 말한다.
그 순서에 맞게 코드의 가장 아래에 순서대로 함수를 호출했다.
그 결과는??

보다시피 조리가 완료도 되기전에 햄버거 가져가라!! 라고 나온다.
우리가 원하는 로직은 햄버거가 완료된 후에 조리 완료!! 를 띄우고 싶다.
그럼 햄버거가져가라() 에도 setTimeout() 을 사용해서 늦게 띄우면 되지 않냐?
사실 우리는 예시를 쉽게 이해하기 위하여 randomInt 라는 변수에 햄버거를 만드는 시간을 저장해서 사용했지만 실제 상황에서는 햄버거든, 커피든, 네트워크에서 데이터를 가져오든 얼마나 시간이 걸리는지 알 수가 없다.
즉, 걸리는 시간을 변수에 저장해서 사용할 수가 없다는 말이다. 얼마 걸리는지 모르니까.
네트워크에서 데이터를 가져오는데 12초가 걸리는데 우리는 12초 인지 15초인지 모르니까 임의로 5초라고 정해서 setTimeout에 전달해도 햄버거가져가라!!! 가 먼저 호출될 것이다.
그렇다고 널널하게 100초를 잡아서 전달하면 무려 88초라는 리소스가 낭비되는 눈물겨운 경우가 발생한다 ㅠㅠ
위에서 비동기의 뜻을 얘기할 때 말한대로 결과가 언제 반환되는지 예측할 수가 없다.
그렇기 때문에 setTimeout을 이용해서 조리 완료!!! 를 늦게 띄우는건 맞지 않다.
하지만 아래처럼 코드를 짠다면 setTimeout을 사용하지 않고, 언제 결과가 반환되는지 우리가 알 필요도 없이 우리가 원하는 결과를 얻을 수 있다.

위의 코드는 원래 코드에서 빨간 줄이 있는 부분만 바뀌었다.
햄버거조리라는 함수에 햄버거가져가라 라는 함수를 전달하였고, 전달한 함수를 호출했다. 이것이 바로 콜백 함수를 사용한 것이다.
콜백 함수에 관해서는 다음 포스트에서 얘기할 것이니 여기선 그렇다고 생각하자.
어쨌든 콜백 함수를 사용했더니 아래 처럼 우리가 원하는 결과를 얻을 수 있었다.

즉, 우리가 비동기 작업(햄버거를 받아오든, 네트워크에서 데이터를 받아오든)을 하면
반드시 해야 할 후처리(햄버거가 완성됐다고 알리던가, 데이터를 원하는 형태로 가공한다거나) 혹은 실행시킬 코드를
비동기 작업이 끝날 때까지 기다린 후 실행 시켜야한다.
그것을 가능하게 해주는 것이 우리가 배울 콜백 함수가 도와준다.
우리는 비동기 작업 후에 반드시 실행시켜야 하는 코드가 있다.
다시 말해 비동기 작업 -> 반드시 실행시켜야 하는 코드 라는 순서로 중간에 어떤 코드도 끼어들지 않고 동기적으로 동작하도록 해야한다.
즉, 비동기 프로그래밍에서 콜백 함수는 비동기 작업이 순차적으로 동작해야할 때 사용할 수 있다.
위의 예시는 서버에서 데이터를 받아올 때도 마찬가지이다.
서버에서 받아온 데이터를 웹페이지에서 사용할 수 있도록 가공하거나, 데이터를 잘 받아왔다고 알려주거나 등, 데이터를 받아온 후 반드시 실행시켜야 하는 코드가 있다면 콜백 함수를 사용한다.