JavaScript 동기와 비동기 방식

seul_velog·2021년 12월 28일
0

JavaScript

목록 보기
22/25
post-thumbnail

자바스크립트와 싱글 스레드

자바스크립트는 싱글 스레드 프로그래밍 언어이다.

  • 스레드(thread)란 프로세스가 할당받은 자원을 이용하는 실행의 단위이다. 하나의 프로세스 안에서 다양한 작업을 담당하는 최소 실행 단위를 스레드라고 한다.
  • 하나의 프로세스에서 하나의 스레드를 실행한다.
  • 코드가 실행되어서 끝난 지점과 다음 코드의 시작 지점이 연결된 형태이다.
  • 각 스레드는 한 번에 하나의 작업만 수행할 수 있으며 순차적으로 실행된다.
    Task A —> Task B —> Task C (다음 작업을 시작하기 전에 이전 작업을 완료해야한다.)

싱글 스레드는 하나의 힙 영역과 하나의 콜 스택을 가진다.

  • 힙(heep)
    : 힙은 변수와 객체의 메모리 할당에 사용되는 비정형 메모리이다.
    Javascript에서 힙은 객체, 배열, 함수와 같이 크기가 동적으로 변할 수 있는 참조타입 값을 저장한다.

  • 콜 스택
    : 함수의 호출 시 지역 변수와 매개 변수가 저장되는 되는 임시 메모리 영역이다.
    하나의 콜 스택을 가진다는 의미는 한번에 한 가지 일 밖에 하지 못한다는 의미이며, 함수를 실행하려면 스택의 가장 위에 해당 함수를 넣게되고 함수에서 리턴이 일어나면 스택의 가장 위쪽으로 함수를 꺼낸다.

✍️ 콜스택과 메모리 힙은 각자의 제한적인 공간이 있으며, 콜스택 메커니즘을 통해 한 번에 하나의 작업만 계속 수행하는 것으로, JavaScript 가 싱글스레드에 중점을 둔 언어라는 것을 알 수 있다.

프로세스와 스레드, 메모리 구조에 대해서는 알아볼 수록 다양하고 심화된 개념이 연결되어 있다는 것을 알 수 있었다. 다음에 이부분에 대해서도 정리를 한번 해봐야겠다. 😀





V8 엔진과 웹 브라우저

자바스크립트 자체 즉, 자바스크립트 엔진(V8)과 웹 브라우저에서 제공하는 API 메소드로 프로그래밍을 하는 것이다.

  • 자바스크립트 엔진 V8의 구성
    자바스크립트 V8 엔진 소스 안에는 하나의 힙과 하나의 콜 스택만 있다.
    setTimeout, DOM, AJAX(HTTP 요청)등과 같은 비동기 메소드가 없다.
  • 자바스크립트 런타임 웹 브라우저의 Web APIs
    setTimeout, DOM, AJAX(HTTP 요청)가 있다.
    이벤트 루프와 콜백 큐를 가지고 있다.

  • 싱글 스레드는 동기적으로 일을 처리한다. 웹 브라우저의 WebAPIs는 비동기적으로 일을 처리한다.

✍️ V8 (자바스크립트 엔진)
: V8은 웹 브라우저를 만드는 데 기반을 제공하는 오픈 소스 자바스크립트 엔진이다. 크롬 웹 브라우저와 Node.js 등에서 사용되고 있다.





동기식 처리 모델

동기식 처리 모델(Synchronous processing model)은 직렬적으로 태스크(task)를 수행한다.

  • 태스크는 순차적으로 실행되며 어떤 작업이 수행 중이면 다음 작업은 대기하게 된다.





비동기식 처리 모델

비동기식 처리 모델(Asynchronous processing model 또는 Non-Blocking processing model)은 병렬적으로 태스크를 수행한다.

  • 태스크가 종료되지 않은 상태라 하더라도 대기하지 않고 다음 태스크를 실행한다.

  • 예를 들어 서버에서 데이터를 가져와서 화면에 표시하는 태스크를 수행할 때, 서버에 데이터를 요청한 이후 서버로부터 데이터가 응답될 때까지 대기하지 않고, 즉시 다음 태스크를 수행한다.
    이후 서버로부터 데이터가 응답되면 이벤트가 발생하고 이벤트 핸들러가 데이터를 가지고 수행할 태스크를 계속해 수행한다.

  • 자바스크립트의 대부분의 DOM 이벤트 핸들러와 Timer 함수(setTimeout, setInterval), Ajax 요청은 비동기식 처리 모델로 동작한다.






동기식 처리 vs 비동기식 처리

  • JavaScript는 동기적이다.
  • 호이스팅(Hoisting)이 된 이후부터 코드가 작성한 순서에 맞춰서 하나하나씩 동기적으로 실행된다.

✍️ 예제 코드를 작성해보자.

1. 동기적인 실행 방법 (sync)

'use strict';

console.log('1'); // 1
console.log('2'); // 2
console.log('3'); // 3
  • 차례대로 '1 → 2 → 3' 순서로 실행되는 것을 볼 수 있다.



2. 비동기적인 실행 방법 (async)

console.log('1');

setTimeout(function(){ 
    console.log('2'); 
}, 1000);

console.log('3'); 
  • 첫번째로 출력되는 것은 '1' 이다. ▶ 동기

  • setTimeout 함수는 바로 실행되지 않는다. setTimeout 함수의 파라미터의 인자로써 사용자가 지정한 함수function 는 조건이 만족되면 실행(전달)시키는 콜백 함수이다.

  • 두번째로 출력되는 것은 '3' 이다. ▶ 동기

  • 마지막으로 출력되는 것으로, 1초 뒤에 '2' 가 출력된다. ▶ 비동기

  • 예제의 setTimeout 은 화살표 함수(arrow function expression)로 표현할 수 있다. ▼

setTimeout(()=> console.log('2'), 1000);

📌 setTimeout() API

  • 전역 setTimeout() 메서드는 타이머가 만료되면 함수 또는 지정된 코드를 실행하는 타이머를 설정한다.
  • setTimeout() 은 비동기 함수로서, 함수 스택의 다른 함수 호출을 막지 않는다. 즉, setTimeout() 을 사용해서 다음 함수 호출을 "일시정지" 할 수는 없다.
  • 이 함수의 콜백 함수는 비동기적으로 호출된다.
setTimeout(() => console.log("첫 번째 메시지"), 5000);
setTimeout(() => console.log("두 번째 메시지"), 3000);
setTimeout(() => console.log("세 번째 메시지"), 1000);

// 콘솔 출력 차례대로 ▼
// 세 번째 메시지
// 두 번째 메시지
// 첫 번째 메시지



3. 비동기 함수 전달 패턴

3-1. Callback 패턴

function order(request, callback) {
  console.log(`${request} 주문이 접수되었습니다.`);
  setTimeout(() => callback(request), 3000);
}

const request = '음료수';

// callback으로 비동기 함수 전달
order(request, (response) => {
  console.log(`주문하신 ${response} 나왔습니다.`);
});

// reseult ▼
// 즉시 실행 : "음료수 주문이 접수되었습니다."
// 3초 후 실행 : "주문하신 음료수 나왔습니다."

3-2. 이벤트 등록 패턴

  • 보통 DOM 을 이용해서 요소에 이벤트를 등록할 때 사용되는 패턴이다.
const btn = document.querySelector('.bth');
// 이벤트 등록으로 비동기 함수 전달
btn.onclick = () => console.log('버튼 클릭!');



4. 비동기 주요 사례

4-1. DOM Element 의 이벤트 이벤트 핸들러

  • 마우스, 키보드 입력 (click, keydown 등)
  • 페이지 로딩 (DOMContentLoaded 등)

4-2. 타이머

  • 타이머 API (setTimeout 등)
  • 애니메이션 API (requestAnimationFrame)

4-3. 서버에 자원 요청 및 응답

  • fetch API
  • AJAX (XHR)



5. 콜백(Callback)함수와 동기 & 비동기

❓ 콜백함수는 항상 비동기일 때 쓸까?
: 콜백함수에도 동기적으로 실행하거나 비동기적으로 실행할 수 있는 방법이 모두 있다.


Synchronous callback


function printImmediately(print){
    print();
}
printImmediately(()=> console.log('hello')); // 동기

Asynchronous callback


function printWithDelay(print, timeout){
    setTimeout(print, timeout)
}
printWithDelay(()=> console.log('async callback'), 2000); // 비동기



6. 이벤트 루프에 의한 setTimeout 콜백함수의 실행

function func1() {
  console.log('func1');
  func2();
}

function func2() {
  setTimeout(function() {
    console.log('func2');
  }, 0);

  func3();
}

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

func1();
  • setTimeout 메소드에 두번째 인수를 0초로 설정하여도 콘솔에 “func1 func2 func3”의 순서로 출력되지 않는데, 이는 setTimeout 메소드가 비동기 함수이기 때문이다.
  • 함수 func1 이 호출 → func1Call Stack 에 쌓인다.
  • 함수 func1 은 함수 func2 를 호출 → 함수 func2Call Stack 에 쌓이고 setTimeout 가 호출된다.
  • setTimeout 의 콜백함수는 즉시 실행되지 않고 지정 대기 시간만큼 기다리다가 “tick” 이벤트가 발생하면 태스크 큐로 이동한 후 Call Stack 이 비어졌을 때 Call Stack 으로 이동되어 실행된다.



📌 check

  • JavaScript는 동기적이다. JavaScript 자체 엔진은 비동기 함수가 없다.

  • JavaScript 런타임(환경: 브라우저, Node.js)에서 제공하는 API를 이용하는 것이다.

  • JavaScript는 싱글스레드 프로그래밍 언어이기 때문에 콜 스택이 하나 밖에 없다.

  • 이러한 비동기 함수를 제공하고 비동기 함수가 콜 스택에 쌓이도록 도와주는 것은 자바스크립트 런타임에서 제공되는 것이다.





reference
hanamon
poiemaweb-js
MDN-setTimeout
thread
callstack
V8 (자바스크립트 엔진)

profile
기억보단 기록을 ✨

0개의 댓글