자바스크립트는 단 하나의 실행 컨텍스트를 갖는다.
실행 컨텍스트는 스택 자료구조를 띄고있다.
이러한 이유로 구조적으로는 동시에 2가지 이상의 함수를 실행할 수 없다.
(실행중인 컨텍스트를 제외하면 나머지 실행 컨텍스트는 모두 실행 대기중인 태스크(업무, task)이다.
태생적으로 자바스크립트 엔진은 한번에 하나의 태스크만 실행할 수 있는 싱글 스레드(single thread) 방식으로 동작한다.
그래서 처리에 시간이 걸리는 태스크를 실행하는 경우 블로킹(blocking, 작업 중단)이 발생한다.
아래 코드는 동기 처리를 보여주는 예시이다.
// Date.now()는 현재 시간을 숫자(ms)로 반환한다.
function sleep(func, delay) {
const delayUntil = Date.now() + delay;
while (Date.now() < delayUntil);
func();
}
function foo() {
console.log('foo');
}
function bar() {
console.log('bar');
}
sleep(foo, 3 * 1000);
bar();
코드 설명
- (함수 선언) sleep 함수는 func과 delay를 매개변수로 받아 현재 시간에서 delay 만큼 후에 func 를 호출한다.
- (함수 선언) foo() 함수는 'foo' 문자열을 출력한다.
- (함수 선언) bar() 함수는 'bar' 문자열을 출력한다.
- 전역(global)에 위치한 sleep 함수가 먼저 실행 컨텍스트에 Push 된다. 인수로는 foo 함수, 3000ms를 받았다.
- 3초 뒤 인수로 받은 foo 함수를 호출하고 실행 컨텍스트에서 Pop 된다.
- 그 다음 전역 순서에 위치한 bar()가 실행 컨텍스트에 Push되고 실행된 뒤 Pop된다.
이처럼 실행중인 태스크가 종료할때까지 다음 실행컨텍스트가 대기하는 방식을 동기(synchronous) 처리라고 한다.
그렇다면 태스크가 종료되지 않은 상태이더라도 다음 태스크를 곧바로 실행하는 방법은 없을까?
이러한 방식이 비동기(asynchronous) 처리 방식이다.
아래 코드를 보자.
function foo() {
console.log('foo');
}
function bar() {
console.log('bar');
}
setTimeout(foo, 3 * 1000);
bar();
setTimeout 함수는 앞서 살펴본 sleep 함수와 유사하게 일정 시간이 지난 후 콜백 함수를 호출하지만
setTimeout 함수는 이후의 함수를 블로킹하지 않고 곧바로 실행한다.
타이머 함수인 setTimeout, setInterval, HTTP 요청, 이벤트 핸들러는 비동기 처리 방식으로 동작한다.
- 동기 처리 방식은 태스크를 순서대로 하나씩 처리하므로 실행 순서가 보장된다는 장점이 있지만
앞선 태스크가 종료할 때까지 이후 태스크들이 블로킹되는 단점이 있다. - 비동기 처리 방식은 현재 실행 중인 태스크가 종료되지 않은 상태라 해도 다음 태스크를 곧바로 실행하므로 블로킹이 발생하지 않는다는 장점이 있지만, 태스크의 실행 순서가 보장되지 않는 단점이 있다.
'Javascript' 카테고리의 다른 글
(JS) Ajax, JSON (stringify, parse 메서드) (0) | 2022.06.09 |
---|---|
(JS) 이벤트 루프(event loop)와 태스크 큐(task queue) (2) | 2022.06.09 |
(JS) 실행컨텍스트 (0) | 2022.06.08 |
(JS) 스코프 (0) | 2022.06.08 |
(JS) 메서드, this (0) | 2022.06.02 |