JS 공부/이론 정리

[JS] JS에서 비동기처리가 왜 그렇게 중요할까?

장아장 2023. 7. 25. 00:32
  • heap : 메모리 할당이 일어난다.
  • call stack : 스택프레임이 생성되어 호출된 함수들이 쌓인다.
  • setTimeOut, DOM, HTTP같은건 V8소스에 없다.
    • V8 런타임과 브라우저가 제공하는 웹 API가 존재한다.
      • 브라우저는 DOM, AJAX, timeout, callback queue, event loop를 가지고 있다.
  • JS : 기본적으로 싱글스레드 런타임을 가지고 있다.
    • 즉, 하나의 콜 스택을 가지고 있다.
    • ex : 제곱을 출력하는 기능을 만든다.
      • 구성함수들
        • 곱하기 (a, b) => a * b;
        • 제곱 (n) = > 곱하기 (n, n);
        • 제곱출력기 (n) => console.log(제곱(n));
      • 콜스택에서 일어나는 일
        1. main 함수 push
        2. 제곱출력기 push
        3. 제곱 push
        4. 곱하기 push
        5. 곱하기 pop
        6. 제곱 pop
        7. 제곱출력기 pop
        8. main pop
      • 즉, error로 나오는 stacktrace는 스택의 마지막부터 처음까지 순서로 나온다.
      • StackOverflow는 이 콜 스택이 까아득 찼다는 뜻이다.
    • 블로킹 : 느린 동작이 스택에 들어있다? => 블로킹!!
      • getSync가 콜스택에 연속적으로 들어간다?
        • 웹에서 동작을 받을 때 까지 스택에 담아 기다리고, 다음 동작을 한다.
        • 연속적으로 3개를 받고, 받은 것들을 출력한다면?
          • 3번 기다리고, 출력을 3번 해야한다.
      • 동기적으로 동작하면 해당 동작들을 기다려야 한다.
        • 반복문들이 동기적으로 동작되기 때문에, 사용을 지양하고 재귀로 처리하라고 하는 것이다.
      • 동기적으로 실행되는 네트워크 요청이 콜 스택을 블로킹한다.
        • 브라우저가 다른 일을 못한다.
        • 결국, 느려진다.
    • 해결책 : 비동기 콜백
      • 코드를 실행하면 콜백을 받고, 나중에 콜백받은 코드들을 실행시키는 방식이다.
      • 아래의 코드를 보았을 때, 출력과 콜 스택을 생각해보자.
      • 어떻게 이렇게 되는거여?
        • 출력
          • hi
          • janghee
          • there
        • 콜스택
          1. main push
          2. console.log('hi') push
          3. console.log('hi') pop
          4. setTimeout(cb, 5000) push
          5. setTimeout(cb, 5000) pop
          6. console.log('janghee') push
          7. console.log('janghee') pop
          8. main pop
          9. console.log('there') push
          10. console.log('there') pop
console.log('hi');

setTimeout(function () {
	console.log('there');
}, 5000);

console.log('janghee');

  • 이벤트 루프, 동시성 역할
    • 브라우저는 단순 런타임 이상을 의미한다.
    • JS는 싱글 스레드로 동작하지만, 웹 API들이 있다
      • 얘네가 스레드를 지원한다.
      • 백엔드에서는 C++ API가 지원한다.
    • 아까 봤던 setTimeout의 기능을 조금 설명하면
      • function : 콜백 함수
      • 5000 : ms(즉, 지금은 5000ms, 5초)
    • 그러면 저 카운트는 어디서 일어나고, 어떻게 다시 콜 스택에 들어올까?
      • webAPIs, 태스트 큐를 이용한다.
        • setTimeout이 호출되면 아래와 같이 동작한다.
          1. 콜 스택에 담는다.
          2. web API에서 타임아웃에 명시된 시간만큼 타이머를 걸어둔다.
          3. 콜 스택에서 빼낸다. (이후, JS는 할 일을 한다.)
          4. web API에서 타이머가 끝났다면, 태스크 큐에 해당 콜백 함수를 push한다.
      • 여기에서 이벤트 루프가 일한다.
        1. 위에서 태스크 큐에 있는 함수와 콜 스택을 확인한다.
        2. 콜 스택은 비어있고, 태스크 큐에는 콜백 함수가 하나 존재한다.
        3. 태스크 큐를 poll해서 콜 스택에 push 해준다.
그러면 setTimeout에서 콜백 시간을 0으로 주면 왜그러는걸까?

  • 기본적으로 이벤트 루프는 콜 스택이 비어있을 때, 태스크 큐의 데이터를 앞에서 하나씩 스택에 push한다.
  • 결국, 타임 딜레이만 없을 뿐, 순서에 대한 딜레이를 줄 수 있다.
    • 또한, setTimeout을 이용한 시간은 정확하게 딜레이를 주는 것이 아니다.
    • 딜레이는 web API에서 대기하는 시간일 뿐, 실제 실행은 더 걸릴 수 있다.
    • 일반 반복문으로 해당 과정을 처리시키면 시간이 오래걸린다
      • ex : forEach
        • 배열에 forEach로 원소마다의 처리가 오래걸리는 동작이라면, 전체적인 과정이 오래걸리게 된다.
        • 이 때 async forEach를 처리해준다면, 더 빠르게 이를 처리할 수 있다.