JavaScript

4-1. 동기처리와 비동기 처리

문정훈 2021. 10. 31. 15:48

1. 배경 지식

비동기 프로그램을 정리하기전에 base가 되는 개념은 js 코드의 '평가'와 '실행'과 실행 컨텍스트 스택의 개념을 알아야함..

 

2. 동기 처리의 개념

VScode에서 .html 코드를 작성하고 이를 웹브라우저에서 실행하면 웹브라우저안에 있는 js 엔진이 .html 파일 안에 스크립트 태그로 작성된 js 코드를 실행하게 된다. 

자바스크립트 엔진은 js의 소스코드를 '평가'와 '실행'을 수행한다. (실행 컨텍스트는 js엔진에 의해 시행되는 것임)

 

모든 js엔진은 하나의 실행 컨텍스트 스택을 가진다. 따라서 한 번에 하나의 테스크만 처리하는 싱글 스레드로 동작한다. 

sleep 메소드는 동기식으로 처리하는 메소드인데 

sleep(func, 3000);
Calc();

위 코드는 3초 동안 기다렸다가 func()함수를 호출한다.  sleep 함수는 동기식 처리 메소드의 예시 중 하나로
동기식 처리는 현재 실행중인 테스크(sleep 메소드)가 종료할 때까지 다음에 실행되는 테스크 Calc()가 대기되는 방식을 말한다. 

동기식 처리에서는 테스크를 순서대로 실행하기 때문에 실행 순서가 보장되는 장점이 있지만, 앞의 테스크가 종료할 때까지 이후 테스크들은 blocking된다는 단점이 있다. 

 

실행 순서 정리=> 

sleep 코드가 실행되면 3초를 기다렸다가 func이 호출되고 func이 끝나면 Calc가 실행된다. 순서대로 처리!!

 

 

3. 비동기 처리의 개념

비동기 처리의 대표 메소드로 setTimeout 메소드가 있다. 

setTimeout(func, 3000);
Calc();

setTimeout메소드는 3초 후에 역시 func를 실행하는 메소드인데 비동기 처리 메소드이다. 

비동기 처리 메소드란 현재 실행 중인 테스크 setTimeout가 종료되지 않은 상태라 해도 다음 테스크 Calc를 곧 바로 실행하는 방식을 말한다. 

Calc 테스크는 비동기식 처리 메소드 setTimeout메소드에 대해서 Non-blocking으로 동작한다고 한다.

 

 

4. 브라우저 환경 

이미지 출처: event-loop.png (1582×1197) (poiemaweb.com)

위 이미지는 브라우저 환경이 가질 수 있는 js엔진과 이벤트 Queue, 이벤트 loop를 나타낸 것이다. 

 

1)  힙(Heap)

힙 영역은 객체가 저장되는 메모리 공간으로 콜 스택 요소인 실행 컨텍스는 힙에 저장된 객체를 참조하게 된다. 

 

2) 콜 스택(Call Stack)

실행 컨텍스트 스택이 콜스택이다.

js엔진은 힙과 콜 스택에서 일어나는 동작들만 관여를 한다. 

js엔진에는 하나의 콜스택이 존재하기 때문에 js 콜스텍에서 처리되는 테스크들은 싱글 스레드로 처리가 된다. 

비동기 처리는 js엔진을 구동하는 웹브라우저 환경 또는 Node.js가 담당한다. 

 

 

3) 테스크 큐, 이벤트 큐(Event Queue)

비동기 함수, 콜백 함수 또는 이벤트 핸들러는 비동기로 처리되는 테스크이다. 이런 비동기 테스크들들이  일시적으로 저장되는 영역이다.

 

4) 이벤트 루프

이벤트 루프란 현재 콜 스택에 실행 중인 컨텍스트가 있는지와 이벤트 큐에 대기 중인 비동기 처리 테스크가 있는지를 반복해서 확인한다.

★만약 콜 스택이 비게 되고 이벤트 큐에 대기 중인 함수가 있다면 이벤트 루프는 이벤트 큐에 있는 처리를 순차적으로 콜 스택으로 이동시킨다.

콜 스택으로 이동한 테스크(함수)는 실행된다.

 

 

5. 비동기 처리 과정 예시

function f1() { console.log('f1'); }

function f2() { console.log('f2'); }

setTimeout(f1, 3000);
f2();

순서1)

위 전체 전역 코드가 '평가' 되어 전역 코드의 실행 컨텍스트가 콜 스택에 push된다. 평가가 끝난 뒤

 

순서2)

전역 코드가 '실행' 되어 setTimeout(f1, 3000); 테스크를 만난다. 

setTimeout 함수가 '평가'되고 setTimeout 함수의 실행 컨텍스트가 push되어 콜 스택(실행 컨텍스트 스택)에서 현재 실행중인 실행 컨텍스트가 된다. ( 여기까지 보면 setTimeout이 이제 실행하기 직전임) 

 

순서3)

setTimeout 함수가 '평가'과정이 모두 끝났고 '실행'과정에 들어가며 그 실행 과정으로 콜백함수(f1)를 호출할려고 하는데 이때 바로 콜백 함수(f1) 호출을 스케줄링(미룬다.)하고 setTimeout은 실행을 끝내고 종료되어 콜 스택에 pop된다.

 

순서4-1) 브라우저가 이 순서를 실행한다. 

브라우저는 타이머를 설정하고 타이머의 만료를 기다린다. 이후 타이머가 만료되면 콜백 함수 f1을 테스크 큐에 push한다. 즉 3초 후에 콜백함수 f1이 테스크큐에 push되어 대기하게 된다. 

대기는 하지만  콜 스택이 비어야 테스크 큐의 작업들이 FIFO로 실행될 수 있기 때문에 3초 후 바로 실행되는 것이 아니다. 

 

순서4-2) js엔진이 이 순서를 실행한다. 

f2함수가 호출되어 이제 f2함수의 실행 컨텍스트가 콜 스택에 저장되고 콜 스택에서 현재 실행중인 실행 컨텍스트가 된다.  그리고 f2함수가 종료되면 f2 실행 컨텍스트가 pop되고 전역 실행 컨텍스트가 pop되어 콜 스택이 비게 된다.

그리고 드디어 테스크 큐에 있던 비동기 처리들이 하나씩 처리되기 시작한다. 

 

순서4-1과 순서4-2 동시에 처리된다.

 

위 설명으로 js 엔진은 싱글 스레드로 동작하지만 브라우저는 멀티 스레드로 동작함을 알 수 있다.