비동기와 JS 엔진

cutiepazzipozzi·2023년 8월 8일
1

Challenge

목록 보기
1/7
post-thumbnail

여기저기 적어두긴 했는데 확실히 내 머릿속에 정리가 안된 것 같아 미션 코드들을 리팩토링 하면서 적어본다!

비동기?

동기도 잘 모르는데, 비동기는 무엇일까?
동기는 코드가 (쓰여진 순서대로) 순차적으로 실행되는 것을 말한다. 비동기는 ('비'니까 동기랑 반대겠쥐) 여러개의 작업이 동시에 실행되는 것을 말한다. 간단히 생각하면 둘의 차이는 코드 순서와 실행 순서가 일치하는지 여부로 알 수 있다.

// 간단한 비동기 예제
console.log("ㅎㅇㅎㅇ");

setTimeout(() => {
  console.log("안뇽안뇽");
}, 1000);

console.log("ㅃㅇㅃㅇ");

//간단한 동기 예제
console.log("ㅎㅇㅎㅇ");
console.log("안뇽안뇽");
console.log("ㅃㅇㅃㅇ");

동기 예제는 쓰인 순서대로(ㅎㅇㅎㅇ -> 안뇽안뇽 -> ㅃㅇㅃㅇ) 실행되고, 비동기 예제는 쓰인 순서와 달리 (ㅎㅇㅎㅇ -> ㅃㅇㅃㅇ -> (1초) 안뇽안뇽) 요렇게 출력된다.

이때 비동기함수 setTimeout에 감싸진 첫번째 인자(console.log~~)는 콜백함수로, 특정함수가 끝난 뒤 어떤 작업을 실행할 때 (보통은) 익명함수 형태로 들어간다. 여러 작업들이 동시에 진행되기 때문에, 진행 상황을 전달하기 위해서도 콜백함수를 사용합니다.

(++ 콜백지옥 : 위에서 인자로 콜백함수를 넘겨줄 때, 많은 콜백함수들이 연쇄적으로 호출되어 코드의 들여쓰기 수준이 깊어지는 현상을 일컫는다.)

++ 함께 설명되는 Blocking

두 개념이 비슷하게 언급되지만 살짜쿵 다르다. Blocking과 Non-Blocking의 차이는 코드의 실행이 다른 코드의 실행을 막는지 여부로 판가름된다. (Blocking은 동기적인 작업에 따라 이후 작업이 막힘)

더 자세히 알아보려면! 갓파님 블로그..

그래서 비동기 왜 씀?

생각해보자. 코드가 무조건 순차적으로만 실행되면, 하나 끝나고 다음 꺼 하고, 그거 끝나면 또 그 다음꺼 하고.. 작업이 여러개가 있다면 시간이 굉장히 많이 들것 같지 않은가?

물론 '단점'도 존재한다. 코드가 작성된 순서대로 실행되는 것이 아니라서 (나같은 왕초보에게는) 흐름 예측이 어렵다.

비동기의 대표주자, Promise

= 비동기 작업의 단위(객체)
const promiseEx = new Promise((resolve, reject) => {});
위의 코드는 기본적인 Promise 객체가 사용되는 코드로, resolve{}에서 실행되는 executor의 작업이 성공하면 실행되는 콜백함수, reject는 실패하면 실행되는 콜백함수이다. (무조건 성공/실패가 결과로 나타난다.)

비동기 작업이므로 언제 끝날지 모르기 때문에 .then, .catch를 통해 후처리 작업을 시켜준다.

  • Promise의 상태는 3가지이다. (fulfilled, rejected, pending)
  • Promise의 특징?은 3가지이다. (then, catch, pending)
  • 위의 new 연산자가 쓰이면 바로 비동기 작업이 시작된다.
function startAsync(age) {
  return new Promise((resolve, reject) => {
    if (age > 20) resolve(`${age} success`);
    else reject(new Error(`${age} is not over 20`));
  });
}

신세대 Async, Await

++ 여기는 더 이해하고 정리가 필요할듯 아직 이해가 안됨 😭🥲

(깃블로그에 잘못적었다) ES8(=ECMA Script 2017)에서 처음 도입됨

async function 함수명(){
	await 비동기_처리_메서드명();
}
  • 비동기 작업 + 후속 처리를 하나의 흐름으로 취급할 수 있다는 장점!
  • Promise와의 차이/장점!
  • async는 함수 선언시 async function ~~() {} 형태로 Promise 객체를 반환하고, await 키워드는 async 함수 안에서, 뒤에오는 Promise 객체가 끝날 때까지 기다렸다가 비동기 처리가 끝나면 실행되게끔 만든다.
    (await 키워드가 Promise에서 등장하였던 then, catch의 역할을 변수에 담아 처리할 수 있게 해줌 -> 동기적으로 실행되는 코드처럼 예측이 조금은 더 쉬워짐)
  • 처리 중 결과에 에러가 발생하면, try-catch문을 통해 처리하면 된다.
  • 모든 비동기를 async 함수로 만들 수 없다.

어떻게 구현되는지 자세히 알고 싶다면

엔진의 작동과정이 설명되기 전에,,

왜 비동기를 설명하면서 엔진 설명을 해야하냐고? 나도 궁금했다!
순수 자바스크립트는 단일 콜스택 구조이기 때문에 비동기가 불가능해 보이나, 브라우저/nodeJS를 활용해 작업을 백그라운드에 요청하여 여러개가 동시에 (비동기!!) 처리되도록 한다.

그래서 우리는 자바스크립트 엔진과 브라우저 환경의 동작 과정을 관찰하며 어떻게 비동기가 실행되는지 제대로 이해해야 한다.

(TMI. nodeJS는 C/C++로 만들어진 libuv(리버브) 라이브러리를 활용해 여섯 단계의 페이즈를 순환하며 콜백 작업을 실행한다. / 이 작동 단계를 더 읽고 작성하고 싶었는데 뇌가 딸려서 fail.. 추후에 추가해보겠음)

자바스크립트 엔진 / 브라우저 환경


(그림은 JS 엔진을 치면 나오는 국룰? 그림인데, 출처를 모르겠다..)

자바스크립트 엔진

두 개로 구성되어 있다.

  1. Heap 영역
    사실 오늘 설명에서 메인이 아니라 간단히 설명하고 넘어간다. 동적인 크기를 갖는 참조값들을 담는 영역이다.

  2. Call Stack 영역
    함수가 실행될 때 생성되는 실행 컨텍스트(함수를 실행하는데 필요한 환경/조건을 담은 객체)들이 담긴다.

    실행 컨텍스트

    실행 컨텍스트는 매우 중요한 내용이기 때문에 따로 기록할 예정이지만, 간단히 설명하자면 3가지로 구성된다.
    1. Variable Environment: 식별자 정보 수집
    2. Lexical Environment: 각 식별자의 '데이터' 추적
    (** 어휘적 환경 -> 사전처럼 정보를 구성했다는 의미)
    3. This Binding

브라우저 동작 과정

  1. 콜 스택에서 쌓인 함수를 pop하여 실행한다.
  2. 비동기 이벤트와 관련이 있는 함수라면, Web API로 넘겨져 실행이 끝나면 이벤트 큐에 들어간다.
    ** Web API (ex. Ajax, Timeout, ..) 는 참고로 멀티스레드 (병렬실행)
  3. 이벤트 루프가 콜 스택이 비어있는지 아닌지 확인하고, 비어있다면 이벤트 큐에 들어있던 콜백 함수를 콜 스택에 넣어준다.

** 이벤트 = 어플리케이션 내에 발생한 응답 가능한 사건
(ex. 사용자가 어떤 버튼을 클릭)

이벤트 루프와 이벤트 큐

이벤트 루프의 필요성

= 자바스크립트 엔진과의 환경 연동을 위해!
(자바스크립트가 구동되는 환경에서 여러 개의 스레드가 연동되는데, 이 스레드들의 코드를 스케줄링하고 실행시킴)

이벤트 루프 동작 과정

  1. 매크로(macro) 태스크 큐에서 가장 오래된 태스크를 실행
  2. 마이크로(micro) 태스크 큐에 있는 모든 태스크 실행
  3. 렌더링 실행
  4. 매크로 태스크 큐에 새로운 매크로 태스크 나타날 때까지 대기
  5. 반복~!

이벤트 큐

  1. 마이크로 태스크 큐 (ex. Promise)
    매크로 태스크 큐보다 우선순위가 높아, 큐에서 마이크로 태스큐가 다 실행되고 비워져야 매크로 태스크 큐가 실행될 수 있다.
  2. 매크로 태스크 큐 (ex. setTimeout)
    우리가 흔히 알고 있는 이벤트 큐는 보통 매크로 태스크 큐이다. 마이크로 큐보다 우선순위가 낮아 한번 실행될 때 마이크로 태스크 큐가 비워졌는지 확인해야 한다.
  3. Animation Frames
    2순위이며, 브라우저 렌더링 담당 큐이다!

참고

코어 자바스크립트
깃블로그 글/아래에 참고 링크 있슴다
깃블로그 글2/아래에 참고 링크 있슴다
async-await 이해

profile
노션에서 자라는 중 (●'◡'●)

2개의 댓글

comment-user-thumbnail
2023년 8월 8일

좋은 글 감사합니다. 자주 방문할게요 :)

1개의 답글