single thread but asynchronous

Creating the dots·2021년 7월 28일
0

Javascript

목록 보기
21/24

Javascript

single thread
one call stack
one at a time

single thread

스레드란?

어떠한 프로그램 내에서, 특히 프로세스 내에서 실행되는 흐름의 단위를 말한다. 일반적으로 한 프로그램은 하나의 스레드를 가지고 있지만, 프로그램 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이러한 실행 방식을 멀티스레드라고 한다

자바스크립트는 싱글 스레드 기반 언어이다. 싱글 스레드는 콜 스택에 함수가 쌓일때 하나가 끝나야지 다음 함수가 작동한다. (synchronous) 만약 어떤 함수가 처리해야하는 것이 많아서 시간이 오래걸린다면, 그 오랜 시간동안 브라우저는 다음 함수를 실행하지 못하고 기다려야 하는 단점이 있다.

따라서 자바스크립트는 비동기적으로(asynchronous) 함수를 실행하기 위해 시간이 오래걸리는 로직은 다른 스레드로 위임하고 다음 로직을 실행한다.(non-blocking) 여기서 말하는 '다른 스레드'는 브라우저에서 제공하는 webAPI를 말한다.

asynchronous programming의 비밀

basic architecture

자바스크립트는 앞서 말한 것처럼 싱글 스레드이지만, 오랜 시간이 걸리는 로직은 '다른 스레드'로 위임하여 마치 멀티 스레드처럼 작동한다고 했다. 이렇게 비동기적으로 작동하는 것은 자바스크립트에서 제공하는 기능이 아니라, 브라우저의 자바스크립트 코어의 최상단에 만들어진 기능으로 브라우저 APIs를 통해 접근이 가능하다.

기본 구조를 정리하자면 다음과 같다. 자바스크립트에서 제공하는 memory heap과 call stack과 브라우저에서 제공하는 web APIs, event loop, callback queue, event table 등이 있다.

  • memory heap (정보를 저장하는 공간)
    메모리 할당이 이루어지는 곳으로 프로그램에 선언한 변수나 함수 등이 들어있다.

  • call stack
    자바스크립트의 코드 실행을 위한 싱글 스레드를 나타낸다. 한줄 한줄마다 코드 실행을 트래킹하는 역할을 한다. 하나의 함수가 실행완료되면, 스택에서 pop되는데, stack이라는 자료구조가 Last in First Out이라는 것을 떠올리면 된다.

  • web APIs
    흔히 API를 설명할때 레스토랑에서 내가 웨이터에게 음식을 주문하는 상황으로 비유를 하곤 한다. 주문을 받고 주방에 요청하여 요청사항을 전달해주는 매개체 웨이터가 API라고 이해할 수 있다. 따라서 API(웨이터)를 통해 내가 구현하고자 하는 응용 프로그램(내가 먹고 싶은 음식)에 필요한 기술을 직접 구현하지 않고도 이미 만들어진 기술(주방에서 만든 음식) 사용할 수 있게 된다.
    브라우저에서 제공하는 API로는 DOM, AJAX, setTimeout 등이 있고, 자바스크립트 코드를 사용할때 데이터를 가져오거나 복잡한 일들을 직접 구현하지 않고 사용할 수 있게 해준다. 웹앱 또는 웹사이트를 만들때 사용할 수 있는 web API들은 다음 링크를 참고하자. https://developer.mozilla.org/ko/docs/Web/API

  • callback queue, event loop
    이벤트 발생 시 실행해야 할 callback 함수가 callback queue에 추가된다. event loop는 stack이 빌때까지 기다렸다가, stack이 비면 callback queue를 차례대로 dequeue한다.
    예를들어, setTimeout함수가 호출되면, stack에서 pop되어 web API로 들어가고, 몇 초 후 event queue로 들어가고, stack이 비면 call stack에 push되어 콜백함수가 실행된다.
    여기서 주의할 점은, setTimeout에 인자로 들어가는 밀리세컨즈(ex. 3초)가 의미하는 것이 3초 후 콜백함수를 실행한다는 것이 아니라 setTimeout함수가 호출됐을때 3초 뒤에 event queue로 push된다는 것을 의미한다. 즉, 최소 3초 이후에 콜백함수가 실행된다.

직접 해보기1

const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("second"),500);
const baz = () => console.log("Third");

bar();
foo();
baz();

//First, Third, Second 순서로 찍힌다.

위 과정을 순서대로 적어보면 다음과 같다.

1. call stack.push(bar()), bar()는 setTimeout 함수 리턴
2. call stack에서 setTimeout과 bar()는 빠져나오고, setTimeout은 webApi로 들어가서 0.5초간 대기
3. call stack.push((foo())되고 pop되면서 console.log("First") 실행
4. call stack.push((baz())되고 pop되면서 console.log("Third") 실행
5.0.5초가 흘러 webAPI에 있던 setTimeout의 콜백함수가 callback queue에 push 되고 call stack이 빌때까지 대기
5. event loop가 stack이 빈 것을 확인하고 event queue.dequeue()하여 stack에 push
6. console.log("second") 실행

직접 해보기2

console.log("A");
setTimeout(()=>{console.log("B"),0));
console.log("C")

//A, C, B 순서로 찍힌다.

두번째 줄은 0초 후에 console.log("B")를 하라는 것이 아니라 0초 후에 콜백함수가 webAPI에서 callback queue로 push된다는 의미이다. 그 사이에 console.log("C")가 stack에 push되어 "C"를 먼저 출력한다. stack이 비었을때 비로소 콜백함수가 stack에 push되어 "B"를 출력한다.

https://towardsdev.com/event-loop-in-javascript-672c07618dc9
https://www.youtube.com/watch?v=8aGhZQkoFbQ&t=237s

profile
어제보다 나은 오늘을 만드는 중

0개의 댓글