[JavaScript] 이벤트 루프 (Event Loop)

minbr0ther·2022년 3월 23일
0

javascript

목록 보기
5/9
post-thumbnail

[10분 테코톡] 🍗 피터의 이벤트루프(17분) 를 보고 정리한 글입니다 :)


1️⃣ 비동기 코드 예시

console.log('하나'); // 1. 

// 1초 뒤에 첫번째 인자로 들어간 콜백 함수를 실행한다.
setTimeout(function() {
  console.log('셋'); // 3.
}, 1000);
// 첫번째 인자 : 특정 함수의 인자로 들어가는 함수 '콜백 함수'
// 두번째 인자 : 1000ms -> 1초(second)

console.log('둘'); // 2. 

🤔 이렇게 동작하는 이유

  • 자바스크립트 엔진이 코드를 진행하다가 setTimeout과 같은 비동기 코드를 만나면, 이 코드를 자바스크립트의 뒷편에서 실행하게 됩니다.

  • '이벤트 루프'는 자바스크립트 코드가 실행되는 자바스크립트 엔진의 뒤편에서 일어나는 어떤 문맥의 일부로써 동작하는 하나의 장치라고 보시면 됩니다.


2️⃣ 콜백 함수 (Callback Function)

  • 다른 함수의 인자로 넘겨지는 함수

  • 콜백 수신 함수에 의해 특정 시점에 실행

    • 동기 콜백의 경우 호출 즉시 실행

    • 비동기 콜백의 경우 나중에 조건을 만족했을때 실행

  • 이벤트 리스너, 타이머 / XMLHttpRequest 요청

//  ☑️ 동기 콜백의 예제

function greeting(name) { 
  console.log( '안녕하세요' + name); // 4. 콘솔 로그 출력
}

function processUserInput(callback) { 
  const name = prompt('이름을 입력해주세요'); // 2. prompt로 이름을 입력받는다.
  callback(name); // 3. 인자로 받은 콜백 함수를 호출한다
}

processUserInput(greeting); // 1. 함수에 함수를 인자로 넣어준다.

3️⃣ 자바스크립트 엔진 (JavaScript Engine)

☑️ 자바스크립트 엔진은 자바스크립트 코드를 해석하고 실행하는 '인터프리터'입니다.

  • 인터프리터(interpreter)는 프로그래밍 언어의 소스 코드를 바로 실행하는 컴퓨터 프로그램 또는 환경을 말합니다.

☑️ 각 브라우저마다 엔진의 종류가 다릅니다.

  • 사파리는 웹킷, 크롬은 V8 등 이런식으로 여러가지가 존재합니다.

☑️ 자바스크립트 엔진은 크게 '힙'과 '호출 스택'으로 구분이 됩니다.

  • 힙(Heap)은 그냥 간단히 '메모리 할당이 일어나는 부분' (변수나 객체들이 저장되는 창고)

  • 호출 스택(Call Stack)'함수가 호출되는 순서대로 쌓이는 스택이다'라고 생각하면 됩니다.

    • 함수 실행시 호출 스택에 해당 함수를 집어넣음

    • 함수 return시(함수의 실행이 끝나면) 호출스택의 맨 위에 있는 해당 함수를 pop한다.

    • 사실은 함수가 아니라 함수 실행 문맥(Execution Context)입니다.


'자바스크립트는 싱글 스레드 언어'

=> 호출 스택을 하나만 사용한다

=> 동시에 하나의 일만 처리할 수 있다.

🤔 그런데 함수가 실행되는 호출 스택이 하나뿐이면서 어떻게 비동기 요청을 지원하고 동시성에 대한 처리를 할 수 있을까요?


4️⃣ 브라우저(Web Browser)의 구조

구조의 자세한 설명은 [JavaScript] 비동기 처리와 자바스크립트 엔진의 동작 에서 확인하실 수 있습니다 :) 이번 포스트에서는 '이벤트 루프'를 좀 더 자세히 알아보겠습니다.

  • setTimeout을 포함해서 DOM 메서드, HTTP 요청 같은 것들은 전부 자바스크립트 엔진의 바깥에 있는 Web API에서 제공하는 메서드들입니다.

  • Web API 메서드들은 작동을 마치면 전부 비동기 메서드들이기 떄문에 작동을 마치고 콜백함수를 콜백 큐에 집어넣습니다. 거기서 콜백 함수들이 실행을 대기하게 됩니다.

  • 자바스크립트 엔진 자체는 싱글스레드이지만 실제로 자바스크립트가 구동되는 환경인 웹 브라우저 에는 여러개의 스레드가 사용됩니다. 조금 더 자세히 말하자면, Web API가 멀티스레드로 동작하는 것입니다. 그리고 자바스크립트 엔진이 이것들과 상호 연동을 하기 위해서 필요한 장치가 '콜백 큐''이벤트 루프'다 라고 생각하면 됩니다.


➰ 이벤트 루프(Event Loop)

☑️ 호출 스택과 콜백 큐를 계속 주시하고 있다.

☑️ 호출 스택이 비어있으면, 먼저 들어온 순서대로 콜백 큐에 있는 콜백 함수들을 호출 스택으로 집어넣는다.


5️⃣ 응용 예시

👀 비동기와 try-catch

document.querySelector('.btn').click(function() { // (A)
  try {
    $.getJSON('/이런저런 주소', function(res) { // (B)
      // 여기서 에러 🚨
    });
  } catch (e) {
    console.log('속보) 에러 발생: ' + e.message);
  }
});

비동기 코드를 사용하다 보면 try-catch가 예상과는 다르게 에러를 잡지 못하는 경우가 발생합니다.

왜 그렇게 되는지 알아보도록 하겠습니다.

  1. 버튼 클릭 이벤트 리스너가 Web API에 등록되어 있는 상황에서 클릭 이벤트가 발생하면 이벤트 리스너의 클릭이 발생하면 콜백 함수가 콜백 큐로 들어가게 됩니다.

  1. 이 상황에서 호출 스택이 비어 있으니까 A가 이벤트 루프에 의해 호출 스택으로 이동하게 됩니다.
    (A의 움직임 : Callback Queue -> Call Stack)

  1. A의 내부에서 getJSON 메서드가 실행되면 http 요청을 보내는 XMLHTTPRequest 객체가 콜백 함수와 함께 webAPI의 생성이 됩니다.

  1. 그러면 getJSON 메서드는 http 요청을 보내는 걸로 자기 할일을 마쳐서 리턴을 합니다. 그리고 A함수 역시 내부에 getJSON만 있었으니까 자기 실행을 마치고 리턴 합니다. 그러면 콜스택이 비워지게 됩니다.

  1. XMLHTTPRequest도 HTTP요청을 보내면서 사라지고, 콜백함수 B가 콜백 큐에 들어가게 됩니다. 그리고 역시나 호출 스택이 비어 있을때 B가 이벤트 루프에 의해서 호출스택으로 이동하게 됩니다. (B의 움직임 : Web API -> Callback Queue -> Call Stack)

    ❗️ 이 상황을 보면 B가 호출스택으로 옮겨지는 이 시점에서는 A가 이미 실행을 마치고 return을 한 상황입니다. 즉 A와 B는 완전히 다른 문맥 속에서 각각 동작을 하고 있습니다.

    ❗️그래서 A 내부에 있는 try-catch문이 B에서 발생하는 에러를 잡아내지 못합니다.


만약에 B에서 발생하는 에러를 try-catch로 잡아내고 싶다면 해답은 간단합니다.

=> B를 감싸고 있던 try-catch 문을 B 내부로 넣어주시면 됩니다 🤭

document.querySelector('.btn').click(function() { // (A)
  $.getJSON('/이런저런 주소', function(res) { // (B)
    try {
      // 여기서 에러 🚨
    } catch (e) {
      console.log('속보) 에러 발생: ' + e.message);
    }
  });
});


🌐 참조 링크

profile
느리지만 꾸준하게 💪🏻

0개의 댓글