Javascript 동기와 비동기가 궁금해 (synchronous / asynchronous)

삼안기·2021년 6월 20일
0

🙆🏽‍♂️ synchronous / asynchronous

며칠 전 맥도날드에 갔는데 요새는 다 키오스크로 바뀌었더라. 주문하려 줄 서는데 앞 두어명이 한참을 고민하고 있는 것이 아닌가. 맥런치 시간을 다 되어가고 있는데, 오랜 고민을 하고 있는 너! 빨리 주문안하면 가격 오른다고 (^-T)

javascript 였다면 비동기로 널 처리했을텐데...

그렇다면 동기(synchronous)가 뭐고 비동기(asynchronous)가 무엇인지 알아보자.


🙋🏽‍♂️ 동기가 뭐죠?

앞서 만난 예시처럼 키오스크에 줄을 서게 되면 앞사람의 주문이 다 끝나야 내 차례가 돌아온다. 키오스크는 한 번에 하나의 주문만 처리하게 되어 있다. 이런 동작을 동기(synchronous), 싱글 스레드라고 한다.

하나의 프로그램은 동시에 하나의 코드만 실행할 수 있다는 뜻이다.

javascript

가장 대중적인 자바스크립트의 엔진은 구글의 V8 엔진이다. V8 엔진은 크롬과 노드 안에서 동작한다. 엔진은 두 가지 주요 요소로 이루어져 있다.

메모리 힙(Memory Heap) 객체는 힙, 대부분 구조화되지 않은 메모리 영역에 할당된다. 변수와 객체에 대한 모든 메모리 할당은 여기서 발생한다.
호출 스택(Call Stack) — 코드가 실행될 때 호출 스택이 쌓인다.

Call Stack

자바스크립트는 싱글 스레드 프로그래밍 언어이다. 싱글 스레드 런타임을 가지고 있는데 결국 한 번에 하나의 싱글 콜 스택(Call Stack)만을 가지고 있다는 것이다.

Call Stack은 자바스크립트 함수 실행 방법 중 하나이다. 함수가 호출되면 Call Stack에 해당 함수 기록이 위에서부터 쌓이게 되고 말했듯이 단일 호출 스택이기 때문에 한 번에 하나의 일만 처리하게 된다. 나중에 쌓인 것 부터 처리가 되어 스택에서 나가기(pop) 때문에 List in First out(LIFO)이라고 한다.

간단한 예시를 통해 처리 과정을 살펴보자.


동기적(synchronous) 처리 예시

function multiply(x, y) {
    return x * y;
}
function printSquare(x) {
    var s = multiply(x, x);
    console.log(s);
}
printSquare(5);

1) 해당 코드를 실행하기 전에는 호출 스택은 비어있다.
2) 맨 아랫줄 printSquare(5)가 실행되어 스택에 쌓인다.
3) printSquare(x) 함수의 multiply(x, x)가 실행되어 스택에 쌓인다.
4) multiply(x, x)가 바로 실행되면서 스택에서 Pop.
5) console.log(s)가 스택에 쌓인다.
6) 25라는 값을 반환하며 console.log(s) 스택에서 Pop.
7) printSquare(5)도 최종적으로 스택에서 Pop 된다.

단일 Call Stack의 문제점

자바스크립트는 하나의 호출 스택만 있기 때문에 하나의 함수 처리가 엄청 느려서 다른 함수 실행에 지장을 줄 때 어떻게 해야할까?

만약 어떤 웹페이지에서 복잡한 이미지 처리를 한다고 해보자. 단일 호출 스택에서 이미지 처리 작업 스택이 엄청 오래 걸려서 다른 작업들이 끝나기만을 기다리게 된다면 사용자는 나쁜 UI를 경험하게 될 것이다. 또한 작업 처리 시간이 오래 걸리면 응답을 멈출 수 있기 때문에 해당 웹페이지를 종료할지 여부를 묻기도 한다. 이럴 때 우리는 비동기 처리를 생각해 볼 수가 있겠다.



🙋🏽‍♂️ 비동기 처리는 Call Stack이 많아서 그래요?

아니! 자바스크립트는 모다? 하나의 Call Stack만 가지고 있다. 다만 이 하나의 Call Stack으로 비동기 콜백을 사용한다. 즉 코드 일부를 실행하고 나중에 실행될 콜백을 제공한다. 바로 실행하는 것이 아닌 특수한 시점에 실행되므로 Call Stack 안에 바로 push 될 필요가 없다.

간단히 말해서 어떤 요청을 보내면 그 요청이 끝날 때까지 기다리지 않고, 응답에 관계없이 바로 다음 동작이 실행되는 방식이다.

비동기 콜백의 처리과정

단일 Call Stack의 문제점에서 본 것과 비교해 보자면 이미지 처리 작업을 하는 중에 쌓이는 다른 함수 호출들을 실행하여 비동기적으로 처리할 수 있는 것이 비동기(asynchronous)이다.

Web API와 Event Queue의 역할

웹브라우저는 자바스크립트 엔진이 제공하지 않는 일부 기능인 DOM 조작이나 AJAX 같은 비동기 처리를 위함 Web API를 제고하고 이를 제어하기 위한 Event Queue를 가지고 있다. Event Queue은 처리할 메세지 목록과 실행할 콜백 함수들의 리스트이다.

이번에도 예시를 통해 살펴보자.



비동기적(asynchronous) 처리 예시

1) 코드를 넣어두고 Call Stack은 비워진 상태로 대기한다.

2) 코드가 실행되면서 글로벌 스택 프레임이 Call Stack에 Push.

3) setTimeout() 함수가 Call Stack에 쌓인다. LIFO 구조로.

4) 이 때 setTimeout()은 브라우저에서 제공하는 Web API이다. Web API는 웹 서버 또는 웹 브라우저를위한 애플리케이션 프로그래밍 인터페이스이다. 브라우저는 Web API에서 타이머를 실행시키고 카운트 다운을 시작한다.

5) setTimeout()의 호출 자체는 실행되었으므로 Call Stack에서 Pop. JS가 아닌 코드로 호출되어 Web API는 요청된 시간동안 대기하게 된다.

6) 실행할 자바스크립트 코드가 없기 때문에 Call Stack은 비워진 상태가 된다.

7) Web API의 timeout 코드가 만료되면 Event Loop(Event Queue)로 코드를 밀어넣어 자바스크립트에 Push할 대기를 한다.
이 때 이곳은 FIFO(First in First out)이다. 먼저 들어온 값이 먼저 나간다는 의미.

8) Call Stack이 비게 될 때마다 자바스크립트 실행환경은 Queue에 대기중인 것을 확인한다. 대기 항목이 있으면 Call Stack으로 Push 되어 함수가 실행된다.

9) 함수가 실행되면 코드 내의 console.log가 호출되어 Call Stack에 쌓인다.

10) console.log의 실행값 hi가 찍히고 console.log는 Pop.

11) 역할을 다 한 Function은 Call Stack에서 제거되고 빈 Call Stack이 된다.



비동기 처리 덕에 이렇게 빠른 웹브라우저를...

곧 공부할 백엔드 과정 전에 자바스크립트 환경에서 동기 / 비동기 처리를 알아보았다. 그런데 만약 Queue에 Event들이 잔뜩 모이게 되면 어쩌지...? 궁금하다. 어쨋든 Event Queue 역시나 대기열 아닌가?
차근차근 알아보면서 공부해 나가야지. 아직 Promise, async / await도 나를 기다리고 있다. 기다렷!



참고

https://new93helloworld.tistory.com/361
https://velog.io/write?id=2809895f-8a36-4037-912f-61c8f2417f5c
https://ljtaek2.tistory.com/142
https://medium.com/@zlatkov
https://velog.io/write?id=2809895f-8a36-4037-912f-61c8f2417f5c

profile
문제를 해결해야지

1개의 댓글

comment-user-thumbnail
2021년 6월 21일

민기님 ! 좋은글 잘읽었습니다. 덕분에 저희 시야도 조금 넓어진것 같네요 감사합니다

답글 달기