Notice
Recent Posts
Recent Comments
Link
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Archives
Today
Total
관리 메뉴

과거의 내가 미래의 나에게

JS 비동기에 대하여 공부하자(2) 본문

카테고리 없음

JS 비동기에 대하여 공부하자(2)

양바삭 2025. 1. 20. 02:44

 오늘은 비동기 처리가 무엇인지에 대한 명확한 정의를 알아보고 JS가 비동기 처리를 어떤식으로 수행하는지에 대해 살펴볼 것이다.

 

 

동기적이고 싱글 스레드로 구성된 JS

JS가 브라우저 혹은 node 등에 의해 실행되기 시작하면 작성된 순서대로 코드가 실행된다. 순서가 오면 해당 코드에 대한 실행 컨텍스트가 만들어지고 콜 스택에 push 되는데 이것이 코드가 실행된다는 것이다.

예를 들어 특정 함수가 순서가 와서 호출당하면 해당 함수는 콜 스택에 실행 컨텍스트로 만들어져 push 되고 함수의 실행이 완료되면 콜 스택에서 pop되어 제거된다.

JS는 싱글 스레드이기에 한 번에 단 하나의 실행 컨텍스트만 실행할 수 있다. 이 뜻은 동시에 2개 이상의 함수가 실행될 수는 없다는 것이다.

함수 2개가 실행되기 위한 방법은 현재 처리 중인 함수가 끝날 때까지 다른 함수는 대기하다가 앞선 함수가 처리가 완료되면 그 이후에야 실행하는 수 밖에 없다. 이를 동기적인 처리라고 하며, 동기 처리는 작업을 순서대로 하나씩 처리하여 실행 순서가 보장되지만 앞선 작업이 종료되지 않는다면 다음으로 넘어가질 않는다. 

< JS 엔진의 구성 >
JS 엔진은 크게 콜 스택과 힙으로 구분되어있다. 콜 스택은 위에서 설명한 바와 같이 실행 컨텍스트가 추가되고 삭제되며 실행 순서를 관리하고, 힙은 객체가 저장되는 메모리 공간이다. 콜 스택의 실행 컨텍스트가 객체의 값을 필요로 할 때 힙에서 저장되어있는 객체값을 참조하여 쓰게된다.

 

JS의 비동기 처리 방법

동기가 순서대로 처리하는 것을 나타냈다면 이와 반대로 작업을 순서대로 처리하는 것이 아닌 앞선 작업이 다 끝나지 않다하더라도 다음 작업을 실행되게 하는 것이 바로 비동기 처리이다.

방금까지만 해도 JS는 싱글 스레드이고 하나의 실행 컨텍스트만 사용하기에 동시에 두 가지 이상 작업을 못한다고 하였는데 비동기 처리는 동시에 여러 작업을 같이 처리할 수 있는 듯 하다. 어떻게 이와 같은 일이 가능할까?

 

이전의 글에서 JS가 여러 작업을 수행하는 방법은 JS 혼자서 하는 것이 아닌 브라우저(혹은 nodejs라던가)라는 비서가 붙어서 업무 수행을 같이 해주는 격이라고 비유를 들었다. 이처럼 비동기 작업을 수행하는 방법은 비서인 브라우저를 통해서 가능해진다.

 

비동기를 구현하기 위해서는 JS의 콜스택 그리고 브라우저의 태스크 큐(=콜백 큐)와 이벤트 루프가 필요하다.

비동기 구현을 설명하기 위해 하나의 함수를 예를 들어 설명해보겠다. 

function startTimer(){
	console.log(9)
	setTimeout(()=>{
    	console.log(8)
    },1000)
    console.log(7)
}

console.log(1)
startTimer()
console.log(2)

 

더보기

글자 편집용으로 보관

  • console.log(1)을 실행 컨텍스트로 만들고 콜 스택에 push한 후 콘솔에 해당 글자를 띄우는 작업을 실행하고 pop으로 제거한다
  • startTimer()을 실행 컨텍스트로 만들고 콜 스택에 push한 후 함수 안의 내용을 순서대로 실행한다.
  • console.log(9)를 실행 컨텍스트로 만들고 콜 스택에 push 한 후 콘솔에 해당 글자를 띄우는 작업을 실행하고 pop으로 제거한다.
  • setTimeout를 실행 컨텍스트로 만들고 콜 스택에 push 한다. 실행 후 WebAPI임을 확인하면 브라우저에 setTimeout이라는 작업을 넘기고 setTimeout 실행 컨텍스트를 콜 스택에서 pop한다.

<aside>

  • console.log(7)를 실행 컨텍스트로 만들고 콜 스택에 push 한 후 콘솔에 해당 글자를 띄우는 작업을 실행하고 pop으로 제거한다.
  • startTimer() 실행 컨텍스트를 pop으로 제거한다.
  • console.log(2)를 실행 컨텍스트로 만들고 콜 스택에 push 한 후 콘솔에 해당 글자를 띄우는 작업을 실행하고 pop으로 제거한다.(동기 작업 끝) </aside>

<aside>

  • 브라우저는 1초간 기다리는 setTImeout 함수를 실행시킨다.
  • 1초가 지난 후, 브라우저는 setTImeout 함수의 첫 번째 인자 내용을 포함하여 콜백 함수를 태스크 큐에 등록해놓는다.
  • 브라우저의 이벤트 루프는 JS의 콜 스택이 계속 확인하면서 비어있는지 확인한다. </aside>

<aside>

  • 브라우저의 이벤트 루프가 JS 콜 스택이 비어있음을 확인하면 태스크 큐에 저장에 놓았던 콜백 함수를 JS의 콜 스택에 push 시킨다.
  • 콜백 함수의 내부에 있던 console.log(2)를 실행 컨텍스트로 만들고 콜 스택에 push 한 후 콘솔에 해당 글자를 작업을 실행하고 pop으로 제거한다.
  • 콜백 함수를 콜 스택에서 pop한다. </aside>

중간에 박스를 보면 나란히 놓여있는 곳이 있는데 이것이 바로 동시에 실행되는 장면이다. 다만 말했듯이 JS가 2개의 일을 하는 것이 아닌 브라우저라는 비서가 한 가지 일을 받아 실행하는 방식이다. 

 

https://wikidocs.net/251900

 

< 태스크 큐와 이벤트 루프 >
태스크 큐: WebAPI의 비동기 작업이 완료된 후 완료되었다는 증표로 생기는 콜백 함수를 저장해놓는 곳. 혹은 이벤트 핸들러를 저장해놓기도 한다.
이벤트 루프: JS와 브라우저의 소통을 담당. 태스크 큐에 완료된 업무가 있는지 계속해서 확인하고 만약 존재한다면 JS의 콜 스택이 비기 까지를 기다렸다가 비었다면 태스크 큐의 업무를 JS의 콜 스택에 옮겨주는 역할을 한다. 비동기 작업의 핵심인듯!
이벤트 루프는 JS의 콜 스택이 비워지기 전까지는 태스크 큐에 있는 업무를 콜 스택으로 옮겨주지 않기때문에 setTimeout같은 함수들이 설정한 시간 뒤에 바로 실행되지 않는다는 것을 명심해야할 것이다. 이에 대한 것은 이전에 공부한 적 있으니 참고(타이머 API (setInterval, setTImeout)는 정확한 시간을 보장 안해: https://yangstorage.tistory.com/107)

 

 

브라우저의 WebAPI

브라우저는 JS 대신 몇몇개의 활동을 대신 실행해줌으로써 JS를 활용하여 비동기적인 효과를 해낼 수 있게끔 도와준다. 그렇다면 브라우저가 제공하는 모든 것은 다 비동기적으로 실행하느냐? 그것은 아닐 것이다. WebAPI로 제공하는 것은 수많이 있지만 어떤 것은 비동기로 작동하고 어떤 것은 동기적으로 처리한다. 예를 들어 위의 주구장창 이야기했던 setTimeout 같은 함수는 타이머함수로서 비동기 함수고, localStorage나 sessstionStorage같은 함수는 동기 함수로써 브라우저가 처리하지만 JS에서 동기적으로 실행된다.

 

브라우저에서 제공하는 비동기 함수 WebAPI의 대표적인 것들은 타이머 관련 함수(setTimeout, setInterval), 이벤트 관련 함수(addEventListener), 네트워크 요청 관련 함수( XMLHttpRequest (AJAX), fetch (HTTP 요청), WebSocket API (실시간 통신), 렌더링 관련 함수(requsetAnimationFrame) 등이 있다.

 

Web이 제공하는 API가 무엇이 있는지는 MDN을 활용하여 확인 가능하다. 각 API들은 설명에 본인이 비동기인지 동기인지 등에 대한 설명도 당연히 있으니 자신이 자주 사용하는 webAPI가 있다면 한 번 쯤 슥 구경하는 것도 좋을 것 같다. 

당연하지만 각 API들은 브라우저에 따라 실행되는게 있고 아닌 것도 있을거고 환경이 https여야만 사용할 수 있을 수도 있기에 꼭 그 내용물도 잘 챙겨보도록 하자

 

 


 

비동기를 위해 JS가 외부로 함수 실행을 맡겨버리기에 외부에서 해당 함수가 언제 끝나고 또 언제 이벤트 루프를 통해 콜 스택으로 들어올 지 몰라서 실행 순서가 보장되지 않는다. 이를 잘 고려하더라도 여러 변수에 의해 예측 못한 상황이 많이 벌어지기도 한다. 그렇기에 프론트엔드 개발자들은 비동기적인 이슈에 항상 노출되어 있는 듯 하다. 

하지만 오늘 이렇게 비동기가 어떤식으로 실행되는지 확실하게 알고가니 이슈가 발생하더라도 좀 더 쉽게 길을 찾을 수 있을 것 같단 생각을 하게 되었고 또 코드를 짜면서 JS에서 지원하는 기능인지 브라우저 자체가 지원하는 기능인지 구분할 줄도 알아야겠다는 생각을 하게되었다.

 

 

Comments