[JS] 비동기 동작 과정

Kyle·2020년 11월 23일
0

javascript

목록 보기
6/18

자바스트립트의 비동기 동작

자바스크립트는 싱글스레드 언어이다.

싱글 스레드란?

싱글 스레드 === 하나의 콜스택으로 작동 ===한번에 한가지 일만 가능

하지만, 이런 싱글 스레드로만 브라우저를 작동한다면???

내가 kyle.com이라는 사이트로 이동을 하고 싶다. kyle.com 링크를 클릭했을 때 자바스크립트는 kyle.com 이 유효한 주소인지 열심히 알아볼 것이다.

이때! 한번에 한가지 일만 하는 자바스크립트는 유효한 주소인지 검사하느라 다른 작동은 다 stop! 하게 된다.

즉, single thread는 request가 끝날 완전히 끝날 때까지 다른 동작은 못한다.

이래서 비동기가 필요하고 중요한 것이 아닐까? 라는 생각이 든다.


비동기 동작 방식

함수가 호출되면 기본적으로 call stack에 쌓이게 된다. 그리고 함수가 끝나면 call stack에서 삭제된다.

하지만 setTimeout 비동기 함수 같은 경우는 살짝 다른 방식으로 실행된다.

예제를 먼저보자

console.log(1);
setTimeout(() => console.log(2), 1000);
console.log(3);

위의 코드의 실행을 예상해보면 당연하게 1,3,2 라고 예상 할 수 있다.

하지만 아래코드를 예상해보면????

console.log(1);
setTimeout(() => console.log(2), 0);
console.log(3);

이코드 역시 1,3,2 순서로 출력된다. 왜 그럴까?

-위 코드의 순서

  1. call stack에 anonymous가 들어간다.
  2. call stack에 console.log(1) 이 들어 왔다가 1을 출력하고 나간다.
  3. call statck에 setTimeout(() => console.log(2), 1000)이 들어왔다 실행하고 나간다. 실행하면서 console.log(2) 는 webAPIs의 0초타이머와 함께 이동한다. 타이머가 끝나면 callback queue로 들어간다.
  4. call stack에 console.log(3) 이 들어 왔다가 1을 출력하고 나간다. 5. anonymous가 끝나고 call stack를 나간다.
  5. callback queue에 있는 console.log(2)가 call stack로 이동해서 출력되고 나간다.
  • webAPIs에 들어간 console.log(2)는 들어간 순간 타이머의 시간이 흐르고 시간이 끝나면 callback Queue(task Queue라고도 한다.)으로 들어간다.

위와 같은 방식으로 비동기 함수가 동작하기 때문에 setTimeout이 0초 여도 바로 실행되는것이 아니라 마지막에 실행 되는 것이다.

이때 Event Loop의 역할은 단순하다. Call StackCallback Queue 두 곳을 지켜 보고 있다가 call stack이 비었을 때! 그때 callback Queue에서 뽑아서 call stack에 넣어주는 역할을 한다.

Event Loop는 call stack이 비었을 때만 전달해주기 때문에 비동기 함수가 많이 실행되어 Callback Queue에 들어있다고 해도 call stack에 올라간 함수가 마무리 할 때 까지 기다렸다가 callback Queue에서 다시 넘겨주고 하는 방식으로 진행된다.

말로는 잘이해가 되지 않을 수 있다. 아래 내가 참조했던 2영상을 보고 이해했다.

  • 크롱이 내준 문제를 동작 순서대로 예상해보자.
const baseData = [1, 2, 3, 4, 5, 6, 100];

const asyncRun = (arr, fn) => {
  arr.forEach((v, i) => {
    setTimeout(() => {
      setTimeout(() => {
        console.log("cb 2");
        fn(i);
      }, 1000);
      console.log("cb 1");
    }, 1000);
  });
};

asyncRun(baseData, (idx) => console.log(idx));

코드를보면 배열 돌면서 setTimeout함수가 있는데 이 setTimeout의 콜백함수로 또 다른 setTimeout함수와 console.log('cb 1') 이 보인다.

  1. cb1의 setTimeout함수의 콜백함수인 setTimeout함수와 console.log('cb 1')가 webAPIs로 들어간다. 배열을 모두 돌면서 전부 들어간다.

    여기서 webAPIs로 들어간 애들은 1초의 타이머가 끝나면 callstack Queue로 들어간다.

  2. forEach가 끝나고 anonymous도 끝나서 callstack이 빈다.

  3. Event Loop가 callstack이 빈것을 확인하고 setTimeout함수와 console.log('cb 1')가 callstack으로 올라간다. setTimeout 함수는 또 다시 콜백함수인 console.log("cb 2") fn(i)는 다시 webAPIs로 들어가고 console.log("cb 1")는 총 7번 출력된다.

  4. 다시 webAPIs에 들어갔던 console.log("cb 2") fn(i)얘네가 callstack Queue로 들어가서 Event Loop가 넘겨준다.

예상결과) cb1*7 / cb2 / 0 / cb2 / 1 / cb2 / 2 ... cb2 / 6

실행결과) 정답이다~

비동기를 이용한 멀티 스레드

우선 이런 표현이 맞는 표현인지는... 잘 모르겠다. 근데 멀티 스레드 처럼 동작한다고 생각한다.

비동기를 이용하면 call stack에서 하나의 동작을 하고 있음에도 webAPIs에서 동작이 일어나고 있기 때문에 동시에 여러 동작을 하고 있다.

자바스크립트는 싱글 스레드 이기 때문에 webAPIs의 다른 멀티스레드 역할을 하는것은 c++로 작성됐다고 한다.

비동기는 싱글스레드인 자바스트립트를 훨씬 다양하게 사용해줄 수있는 매우 중요한 것이다. 비동기가 자바스크립트에서 가장 중요한 것이라고 말하듯 비동기에 대해 더욱 자세히 알아봐야 겠다.

참조 : https://www.youtube.com/watch?time_continue=592&v=8aGhZQkoFbQ&feature=emb_logo

https://www.youtube.com/watch?v=wRPcxR1M7Uc

profile
Kyle 발전기

0개의 댓글