JS - Event Loop , Stack, Queue

남윤하·2024년 2월 17일

JS

목록 보기
4/9
post-thumbnail

🎪 JavaScript의 비동기 처리

  • 웹브라우저는 우리가 짠 자바스크립트 코드를 실행시켜준다.

🧨 single threaded

  • single threaded로 동작한다는 것은, Stack이라는 공간이 javascript 엔진에 단 한개라는 것을 의미하며, 한번의 하나의 일만 처리한다는 것을 의미한다.
  • Memory Heap에는 우리가 선언한 변수들을 저장
  • Call Stack은 함수를 호출해서 한줄 한줄 쌓는다. Call Stack을 통해서 실행중인 함수를 알 수 있다. (이 때 쌓이는 것은 Execution Context)
  • WebAPIs는 브라우저가 제공하는 API
  • Callback Queue는 콜백이 queue처럼 쌓인다. WebAPI가 실행되면 CallbackQueue에 Callback함수가 쌓인다.

🧨 Call Stack

참고: https://www.youtube.com/watch?v=8aGhZQkoFbQ

  • 함수를 실행하면 스택에 해당 함수를 넣고, 함수에서 리턴이 일어나면
    Stack의 가장 위쪽에서 해당 함수를 꺼내게 된다. 이게 콜 스택이 하는 일의 전부다
  • 위의 코드를 실행하면 코드 자체를 말하는 메인 함수를 스택에 집어넣게 된다.
  • 이제 왼쪽의 함수들를 정의하게 되고, 마지막에 printSquare를 만나게 되며, printSquare(4)는 함수 호출이므로 스택에 함수를 추가한다.
  • 이렇게 같은 방식으로 square호출 > multiply를 차례로 호출한 뒤에 return 절을 만나서 a와 b를 곱한 결과를 반환한다.
  • 무엇인가를 return 할 때마다 stack 맨 위에 있는 것을 꺼낸다.
  • 다시 printSquare까지 돌아온다. 위에선 return이 보이지 않지만 암묵적으로 리턴한다.
  • 이것이 콜스택이다!

  • 위의 함수를 호출할 때 에러가 난다면 크롬 개발자 도구에서는 위에서처럼 스택의 꼬리를 물면서 Oops!를 표시하게 된다.
  • 이는 에러가 발생한 스택의 상태를 보여주는 것이다
    uncaught error는 foo에서 생겼는데 bar가 호출, bar는 baz에게서 호출

"스택을 날려먹었다"

  • foo함수가 foo 함수를 호출
    main함수가 foo를 호출한후 무한하게 foo함수는 foo함수를 호출x1000000000

"느려진다 = blocking 현상"

  • 그저 느리게 하는 코드
  • 네트워크 요청이나 이미지 프로세싱은 느리며, 느린 동작이 스택에 남아있는 것을 보통 블로킹이라고 한다.

예시

  • 동기적으로 ajax요청을 보내는 jQuery 함수 getSync

  • 코드를 실행해서 getSync를 호출하면 응답을 기다리게 된다.

  • 이렇게 다음줄로 넘어가고 기다리는 반복을 하게된다.

  • 프로그래밍 언어에서 싱글 스레드라고 하는 것은 여러개의 스레드를 사용하지 않는다는 의미이다.

  • 네트워크 요청을 하고는 끝날때까지 기다린다.

  • 이때, 문제는 웹브라우저에서 코드가 실행된다는 것이다.

  • getAsync와 같이 요청을 보냈을 때에는 아무 것도 실행시킬 수 없다.
    브라우저는 모든 리퀘스트가 완료될 때까지 멈춰있는다.

  • 리퀘스트가 끝나기전에 어떤 것을 실행 한다면, 동기적으로 실행되는 네트워크 요청이 콜 스택을 블로킹 하여, 브라우저는 다른 일들을 할 수없다. 렌더링이나 다른 코드를 실행하지 못하고 그냥 멈춰버린다.

  • 유려한 UI를 만들기 위해서는 콜스택을 멈추게하면 안된다.
    => 이를 해결하기 위해선 비동기 콜백이 필요하다.

🧨 Web API의 비동기 처리

  • 자바스크립트는 싱글스레드로 동작하지만, 비동기 작업 처리를 위해 웹API를 활용하여 멀티스레드와 유사한 효과를 얻는다.

  • 웹 브라우저나 Node.js와 같은 환경에서 제공하는 Web API는 백그라운드에서 동작하며, 여러 작업을 병렬로 처리할 수 있다.

  • 예를 들어, setTimeout, XMLHttpRequest, fetch 등은 Web API를 사용하여 비동기적으로 동작하며, 이는 브라우저의 백그라운드 스레드에서 처리된다.

🧨 이벤트 루프의 역할

  • 이벤트 루프는 콜 스택이 비어있을 때, 콜백 큐에서 콜백 함수를 꺼내와 실행하는 역할을 한다.

  • Web API에서 비동기 작업이 완료되면 해당 작업의 콜백 함수가 콜백 큐에 쌓이게 됩니다.

  • 이벤트 루프는 콜 스택이 비어질 때마다 콜백 큐에서 콜백 함수를 꺼내와 콜 스택에 넣어 실행한다.

🧨 비동기 작업의 처리 순서

  • 비동기 작업은 Web API에 의해 백그라운드에서 처리되므로, 콜 스택이 차단되지 않고 동시에 다른 작업을 수행할 수 있다.
  • 이후 비동기 작업이 완료되면, 해당 작업의 콜백 함수가 콜백 큐에 추가되고, 이벤트 루프를 통해 순차적으로 처리됩니다.

🧨 브라우저의 백그라운드 스레드 활용:

  • Web API는 브라우저의 백그라운드 스레드에서 동작하므로, 멀티스레드와 유사한 효과를 제공한다.
  • 이를 통해 여러 비동기 작업을 동시에 처리하면서도, 싱글스레드로 인한 블로킹을 피할 수 있다.
  • 이와 같은 방식으로 자바스크립트 엔진은 싱글스레드로 동작하면서도 웹API를 활용하여 비동기 작업을 효과적으로 처리한다.
  • 이벤트 루프는 콜백 큐에 있는 작업을 콜 스택으로 이동시켜 실행함으로써, 비동기 작업의 순서를 제어하고 동시에 여러 작업을 효율적으로 처리한다.

🧨 Promise 처리

  • Promise는 동기처리이다

  • Promise자체는 동기이지만 then을 만나면 비동기로 동작하게 된다.
    (엔진은 then을 비동기로 인식한다) 따라서 then으로 인해 Promise는 WebAPI로 넘어가게 된다.

  • WebAPI에 timeOut과 Promise 둘 다 있으면 누가 먼저 끝날지는 모르지만 timeOut이 먼저 끝난다고 가정해 callback queue에 timeOut, Promise 순으로 들어간다.

  • 이 때 Event Loop는 Call Stack안에 Context 유무를 확인 하고 Callback Queue에서 then의 익명함수를 먼저 CallStack으로 보낸다.
    timeOut이 먼저 들어왔음에도 then의 익명함수가 먼저 Call Stack으로 들어간 이유는 우선순위 때문이다

출력결과

🎉 Promise가 우선순위인 이유

  • Microtask Queue(Job Queue)가 가장 먼저 우선순위를 가지는데, Promise는 여기에 해당하고, Task Queue(Event Queue)에 timeOut이 해당 하기 때문이다.
profile
개발 일지 블로그

0개의 댓글