Javascript 비동기 프로그래밍

fgStudy·2022년 5월 22일
1

자바스크립트

목록 보기
22/26
post-thumbnail

동기 처리와 비동기 처리

실행 컨텍스트 스택

함수 코드의 평가를 마치고 생성된 함수의 실행 컨텍스트가 실행 컨텍스트 스택에 푸시된다는 것은 함수 실행의 시작을 의미함

여러개의 함수가 호출된 순서대로 실행되는 것은 호출된 순서대로 해당 함수의 실행 컨텍스트가 만들어지고 실행 컨텍스트 스택에 푸시되기 때문임

즉 함수의 실행 순서는 실행 컨텍스트 스택이 관리한다

싱글 스레드인 자바스크립트 엔진

그런데 자바스크립트 엔진은 실행 컨텍스트 스택이 딱 1개

한 번에 최대 1개의 함수만 실행할 수 있다는 뜻

즉 자바스크립트 엔진은 한 번에 하나의 테스크만 실행할 수 있는 싱글 스레드 방식으로 동작함

처리 시간이 오래 걸리는 테스크가 실행되면 대기 중인 테스크는 중단되는 블로킹이 발생

동기 처리

// sleep 함수는 일정 시간(delay)이 경과한 이후 콜백 함수(callback)를 호출
function sleep(callback,delay){
  const delayUntil = Date.now() + delay;
  // 현재 시간이 delay를 더한 delayUtil보다 작으면 계속 반복
  // 즉 delay가 경과될 때까지 sleep 함수 반복
  while (Date.now() < delayUntil);
  // delay가 경과한 이후 콜백함수(callback) 호출
  callback();
}

function a(){
  console.log('a');
}
function b(){
  console.log('b');
}

// sleep 함수는 3초 이상 실행
sleep(a,3000);
// b 함수는 sleep 함수의 실행이 종료된 이후에 호출되므로 3초 이상 블로킹
b();
// (3초 경과 후) a 호출 -> b 호출

sleep 함수는 3초 후에 a 함수 호출
이 때 b 함수는 sleep 함수 실행이 종료된 이후에 호출되므로 3초 이상 호출되지 못하고 블로킹

이처럼 현재 실행 중인 태스크가 종료할 때까지 다음에 실행될 태스크가 대기하는 방식을 동기 처리라 한다.

동기처리는 태스크를 순서대로 하나씩 처리하므로 실행 순서가 보장된다는 장점이 있지만, 앞선 태스크가 종료할 때까지 이후 태스크들이 블로킹되는 단점이 있음


비동기 처리

위의 코드를 타이머 함수 setTimeout를 이용해 비동기적으로 수정해보자

function a(){
    console.log('a');
}
function b(){
    console.log('b');
}

// 타이머 함수 setTimeout은 일정 시간이 경과한 이후에 콜백 함수 foo를 호출
// 타이머 함수 setTimeout은 b를 블로킹하지 않음
setTimeout(a,3000);
b();
// b 호출 -> (3초 경과 후) a 호출

setTimeout은 일정 시간이 경과한 이후에 콜백 함수를 호출하지만 setTimeout 함수 이후의 태스크를 블로킹하지 않고 곧바로 실행

이처럼 현재 실행 중인 테스크가 종료되지 않은 상태여도 다음 테스크를 곧바로 실행하는 방식을 비동기 처리라 한다.

비동기 처리는 현재 실행 중인 태스크가 종료되지 않은 상태라 해도 다음 태스크를 곧바로 실행하므로 블로킹이 발생하지 않는다는 장점이 있음. 하지만 태스크의 실행 순서가 보장되지 않는다는 단점이 있음

타이머 함수와 HTTP 요청, 이벤트 핸들러는 비동기 처리 방식으로 동작



이벤트 루프와 테스크 큐

자바스크립트는 싱글 스레드이지만 브라우저가 동작하는 것을 보면 많은 태스크가 동시에 처리되는 것처럼 보인다.

이처럼 자바스크립트의 동시성을 지원하는 것이 브라우저에 내장된 이벤트 루프

자바스크립트 엔진

자바스크립트 엔진을 크게 2개의 영역으로 구분하면

  1. 콜 스택 = 실행 컨텍스트 스택
  2. 힙 : 객체가 저장되는 메모리 공간, 실행 컨텍스트는 힙에 저장된 객체를 참조, 힙은 동적 할당을 위해 구조화 되어있지 않다

자바스크립트 엔진은 단순히 태스크가 요청되면 콜 스택을 통해 요청된 작업을 순차적으로 실행


브라우저 환경

자바스크립트 엔진은 소스코드의 평가와 실행을 담당하고
그 외의 비동기 처리를 위한 모든 처리는 브라우저나 Node.js가 담당함

이를 위해 브라우저 환경은 태스크 큐와 이벤트 루프를 제공

  1. 테스크 큐 (task queue, event queue, callback queue)
    : 비동기 함수의 콜백 함수 or 이벤트 핸들러가 일시적으로 보관되는 영역

  2. 이벤트 루프 :
    콜 스택이 비어있는지, 테스크 큐에 대기 중인 함수가 있는지를 반복해서 확인하여 비어있으면 테스크 큐에 있는 함수를 콜 스택으로 이동시킴 -> 이동된 함수는 실행됨


예시

// b 함수가 먼저 실행되고 a가 나중에 실행됨
function a(){
	console.log('a');
}
function b(){
	console.log('b');
}

setTimeout(a,0);
b();
  • 전역 코드가 평가되고 전역 실행 컨텍스트가 콜 스택에 푸시

  • 전역의 setTimeout 함수가 실행되어 콜백 함수 스케줄링을 마치고 콜 스택에서 pop. 이 때 호출 스케줄링, 즉 타이머 설정과 타이머가 만료되면 콜백 함수를 태스크 큐에 푸시하는 것은 브라우저의 역할

    • 브라우저는 타이머 설정 후 타이머가 만료되면 a함수를 테스크 큐에 푸시되어 대기. 0ms로 지정했지만 4ms이하는 4ms로 설정됨
      - b 함수가 호출되어 실행 컨텍스트를 생성하고 콜 스택에 푸시, b 함수 실행 마친 뒤 콜 스택에서 팝
  • 더이상 실행할 전역 코드가 없으므로 전역 실행 컨텍스트 콜 스택에서 팝

  • 이벤트 루프가 콜 스택이 비었음을 감지하고 테스크 큐에서 기다리던 a를 콜 스택으로 푸시, a실행 후 팝


정리

setTimeout은 설정한 타이머가 만료되면 콜백 함수를 테스크 큐로 푸시하는 것이고 콜 스택이 비어야 테스크 큐에서 콜 스택으로 이동하기 때문에 설정한 시간에 정확히 호출되지 않고 지연될 수도 있음

setTimeout이 호출되어 실행되는건 자바스크립트 엔진이
타이머 설정과 테스크 큐에 등록하는 처리는 브라우저가 한다

자바스크립트 엔진은 싱글 스레드로 동작하고 브라우저는 멀티 스레드로 동작

profile
지식은 누가 origin인지 중요하지 않다.

0개의 댓글