동작원리 6 - JS,브라우저(이벤트 루프)

김영현·2023년 9월 21일
0

동작원리

목록 보기
6/7

서론

JS는 기본적으로 싱글스레드.
싱글 스레드인데, 어떻게 비동기적으로 처리할까?
바로 브라우저의 event loop기능 덕분! 브라우저는 JS가 아니니, 멀티 스레드로 활용 가능하다

이벤트 루프


https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop

MDN에서 이벤트 루프를 시각화 해주었다.

  • Heap : 객체가 들어감
  • callstack : 함수의 호출
  • task queue : 처리할 메시지들

메시지?
감이 안온다.
일단 스택부터 훑어보자

call stack

실행 컨텍스트가 추가-제거 되는곳이 바로 콜 스택이다.

function foo(num) {
	const a = 10;
  	return a + num;
}
function bar(num) {
	const b = 22;
  	return foo(num*b);
}
const result = bar(10);
  1. bar()가 실행되었다. 스택에 bar()추가.
  2. bar()를 읽고있자니, foo()가실행되었다. 스택에 foo()추가 => bar()위에 foo()
  3. foo()가 반환되면 스택에서 제거된다. => 스택에는 bar()가 남아있음.
  4. bar()가 반환된다. 스택은 비어있다!

참고로 클로저같이 외부함수가 날아가도 남아있는 지역변수실행 컨텍스트의 스코프 체인 영역에 할당되어있으니 접근가능.

task queue

큐에는 메시지가 담긴다. 메시지란

  • 비동기 작업 완료: 비동기 작업(예: 타이머, 네트워크 요청, 파일 읽기 등)이 완료되면 해당 작업의 콜백 함수나 이벤트 핸들러가 호출된다. 이때, 비동기 작업이 완료됨을 알려주는 것.
  • 이벤트 발생: 웹 페이지에서 발생하는 이벤트(예: 클릭, 키보드 입력, 마우스 움직임 등)도 메시지로 처리된다.
  • 콜백 함수 실행: 타이머나 프로미스와 같은 비동기 작업에서 지정된 콜백 함수도 메시지다.

살짝 이해가 갈랑말랑한다. 아래의 예시로 보자

  • 참고사항 : setTimeOut()는 두개의 인자를 받는다.
    1. 에 추가할 메시지
    2. 시간 값(디폴트 0) => 큐에 추가하기까지 기다릴 (최소)시간
    '최소'가 붙은 이유는 큐와 스택이 비어있지 않다면 지연시간이 발생하기 때문이다.

궁금한 점.
'모던 자바스크립트 deep dive'에는 setTimeOut에 이런설명이 있다.
지연시간이 4ms이하인 경우 최소 지연시간4ms가 지정된다
하지만 MDN에서 보면 5개 이상 중첩됐을 시 최소지연시간 4ms가 보장된다 라고 나와있다.
뭐징?

const seconds = new Date().getTime() / 1000;
setTimeout(function () {
  // "2"를 출력, 즉 500밀리초가 지난 후 즉시 실행된 것이 아니라는 것
  console.log(`${new Date().getTime() / 1000 - seconds}초 후 실행됩니다.`);
}, 500);

while (true) {
  if (new Date().getTime() / 1000 - seconds >= 2) {
    console.log("좋아요, 2초간 반복했습니다.");
    break;
  }
}

위의 예시는 setTimeOut()의 콜백함수를 큐에 넣었지만
다른 메시지들이 큐에 들어가있어 늦게 출력되는 상황이다.

재밌는 예시도 있다

(() => {
  console.log("시작");

  setTimeout(() => {
    console.log("콜백 1: 콜백 메시지");
  }); // 기본적으로 시간 값을 0으로 가집니다.

  console.log("평범한 메시지");

  setTimeout(() => {
    console.log("콜백 2: 콜백 메시지");
  }, 0);

  console.log("종료");
})();

// "시작"
// "평범한 메시지"
// "종료"
// "콜백 1: 콜백 메시지"
// "콜백 2: 콜백 메시지"

언뜻 보면 시작 => 콜백1 => 콜백2 => 종료같지만
결과는 다르다.

  1. 전역 코드 평가되서 전역 실행 컨텍스트 생성되서 콜스택에 푸시
  2. 전역코드 실행 시작. 시작가 호출되어 실행 컨텍스트 생성되고 콜스택에 푸시.
    2-1. 실행되어서 콜스택에서 제거됨. => "시작"출력
  3. 콜백1을 가진 setTimeOut()이 호출되어 실행컨텍스트 생성되고 콜스택에 푸시.
    3-1. 이때 setTimeOut의 시간을 세는 브라우저의 Web Api타이머 함수도 함수 실행 컨텍스트 생성.
  4. 콜백1가진 setTimeOut()실행. 콜 스택에서 제거. 타이머 만료되면 콜백함수브라우저가 태스크큐에 푸시 할것임
  5. 브라우저는 타이머(0)의 만료를 기다림. 바로 만료되었으니,콜백1태스크 큐에 푸시됨.
  6. 5번의 작업과 병행처리함. 왜냐면 5번은 브라우저가 처리, 6번은 js엔진이 처리.
    평범한메시지가 호출되어 실행컨텍스트 생성, 콜스택푸시, 실행, 제거 => 평범한 메시지출력
  7. 콜백1과 마찬가지로 콜백2를 가진 setTimeOut함수도 같은 과정을 거쳐서 콜백2를 태스크 큐에 추가함.
  8. 종료가 호출되어 실행컨텍스트 생성, 콜스택 푸시, 실행, 제거 => 종료출력.
  9. 이후 태스크 큐에 남아있던 콜백1,콜백2출력.

=> task queue에 있는 작업들은 현재 스코프에서 호출될 함수 들, 즉 call Stack이 아주 완전히 비어야만 추가됨.

코드가 다르지만 아래의 과정을 보면 보다 쉽게이해가능함.

micro task queue

task queue와는 별도의 큐. Promise, async-await등의 후속 처리 메서드의 콜백함수가 일시 저장되는 곳.
기존 task queue보다 우선순위가 높기에, call stack이 비면 먼저 이곳에서 태스크를 꺼내온다.

animation frames

먼저 requestAnimationFrame에 대해 알아야한다.
애니메이션은 프레임 단위로 이루어져있다. 60프레임이라면 초당 60개의 사진을 보여준다는 의미다.
=> 초당 16ms정도를 넘기면 안된다.
본래 애니메이션 구현 방법은 setTimout, setInterval처럼 타이머 관련 함수를 이용했다.
requestAnimationFrame이 등장하기 전까지 말이다.

타이머 관련 함수는 브라우저의 백그라운드에서 무슨일이 일어나던 신경쓰지 않는다.
=> 알트탭 하거나 페이지에서 보이지 않아도 진행됨. 메모리 낭비.
또한 리페인트가 일어났을때 프레임이 누락될 수 있음.
=> 리플로우는 위치, 색을 계산하는 과정. 리페인트는 실제로 적용되는 과정. 이게 끝나기도 전에 다음 프레임이 호출된다면, 버벅임 발생.
JS는 싱글 스레드이기에, 다른작업이 추가되도 프레임 누락이 생길 수 있다.

그래서 등장한게 requestAnimationFrame이다.

requestAnimationFrame(callback)이런식으로 콜백함수를 넘겨주고, 재귀적으로 사용한다.
이 메소드는...

  • 리페인트가 일어나기전에 콜백함수를 실행해준다.
  • 화면 주사율에 맞춰 프레임을 조정해준다
  • 애니메이션을 정지시킬 수도 있다.

https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#list-of-animation-frame-callbacks
그런데, 콜백함수animation frame call back map에 저장된다.

가 아니다. 이다.
완전히 처음 들어봐서 이해하는데 시간이 좀 걸렸다. ㅠㅠ
그런데 animation frames라는 단어는 없다...뭐지?!


어쨋든...렌더링 루프, animation frame callbacks가 완전히 비어야지만 다음 태스크 큐를 꺼내온다(마이크로 태스크 큐부터)

느낀점

완전히 처음 습득하는 내용은 어렵다. 더군다나 국내에 잘 나와있지 않거나, 잘못된 정보가 있는 경우에는 더 그렇다.
정보의 바다에서 살아남기위해 교차검증은 필수다...특히 공식문서와의 검증은 필수다.
그리고 이벤트 루프에 대해 정확히 할게되었다. 뜬구름 잡듯이 알고있던 지식을 구체화할 때의 쾌감은 장난 아니다

profile
모르는 것을 모른다고 하기

7개의 댓글

comment-user-thumbnail
어제

Many thanks for that publish as well as excellent ideas.. actually We additionally believe that effort is actually the most crucial ingredient of obtaining achievement. 해외선물 코스피

답글 달기
comment-user-thumbnail
어제

Amaze! Just what exactly watch opener the following posting is to do. Significant ly prized, saved as a favorite, I actually can’t bide time until extra! agenolx slot

답글 달기
comment-user-thumbnail
약 9시간 전

You make so many great points here that I read your article a couple of times. Your views are in accordance with my own for the most part. This is great content for your readers.해외선물 개발

답글 달기
comment-user-thumbnail
약 9시간 전

Wow, What a Excellent post. I really found this to much informatics. It is what i was searching for.I would like to suggest you that please keep sharing such type of info.Thankspestoto

답글 달기
comment-user-thumbnail
약 9시간 전

Wow, this is fascinating reading. I am glad I found this and got to read it. Great job on this content. I liked it a lot. Thanks for the great and unique info. 해외선물 분양

답글 달기
comment-user-thumbnail
약 6시간 전

I got too much interesting stuff on your blog. I guess I am not the only one having all the enjoyment here! Keep up the good work. 해외선물 개발

답글 달기
comment-user-thumbnail
약 4시간 전

1xBet gives you a 130% bonus when you sign up with code 1X200FOX. Enjoy safe, fun, and rewarding betting every day. 1xbet promo code for registration

답글 달기