본문 바로가기

개발/Front-end

Event Loop에 대하여

반응형

일단 자바스크립트는 싱글스레드이다.

 

그렇기에 단 하나의 호출 스택(Call Stack)을 가지며 모든 함수들은 실행될 때 이 Call Stack을 거쳐서 호출된다.

하지만 자바스크립트가 동작함에 있어서 속도를 더 증가시키기 위해 비동기 함수가 존재한다. 대표적으로 setTimeOut, setInterval등이 있는데 이들은 비동기 함수로써 브라우저에서 웹 API로 동작하여 실행시킨 뒤 콜백을 event queue 에 등록시킨다. 그 이후 Call Stack이 비게되면 이를 event queue에서 Call Stack으로 밀어주게 되는데 이를 eventloop라고 부른다.

 

Call Stack

JS는 단 하나의 호출 스택을 사용한다. 이러한 특징 때문에 JS의 함수가 실행되는 방식을 "Run to Completion"라고 한다. 이는 하나의 함수가 실행되면 이 함수의 실행이 끝날 때까지 다른 어떤 task도 수행될 수 없다는 의미이다. 요청이 들어올 때마다 순차적으로 호출 스택에 담아 처리한다. 메소드가 실행될 때, Call Stack에 새로운 프레임이 생기고 push 되고 메소드의 실행이 끝나면 해당 프레임은 pop되는 원리이다.

function foo(b){
	var a = 10;
	return a+b;
}
function bar(x){
	var y =2;
	return foo(x+y)
}
console.log(bar(1));

 

다음 코드를 살펴보자

일단 test1이 출력이 되고 test2가 호출되면서 setTimeout 함수가 실행되고 콜 스택에 들어간 다음, 바로 빠져 나온다. 그리고 내부에 걸려있던 핸들러(익명함수)는 콜스텍에 들어가서 바로 실행되지 않는다. 이 부분이 중요하다. 이 핸들러는 call stack영역이 아닌 event queue 영역으로 들어간다. 그리고 test3함수가 콜스텍에 들어간다.

test()이 실행되면서 test3이 출력되고, 작업에 마친 test3가 Call Stack에서 pop된다. 이어서 test2함수와 tset1 함수까지 Call stack에서 pop된다. 이 때 이벤트 루프의 콜스택이 비어있게 된다. 바로 이 시점에서 queue의 head에서 하나의 event를 가져와서 Call Stack으로 넣는다. 이 이벤트는 setTimeout함수 내부에 있던 익명함수이다. 이제서야 이 함수가 실행된다.

즉, test3가 끝나고 test2가 끝나고, test1이 끝나고 나서야 이벤트 루프에 의해 하나의 event가 dequeue된 다음 콜스택으로 들어가서 실행된다. 그러므로 이벤트에 걸려있는 핸들러는 절대 먼저 실행될 수 없다.

비동기 함수들을 내가 만든 함수를 등록시키기 위해서는 여러가지 방법이 존재하는데

  1. AJAX 방식으로 콜백을 등록시킨다.

⇒ 이 방식으로는 무한으로 콜백 함수가 붙어 이해하기가 어려운 콜백 헬이 발생하여 가독력이 떨어진다. 콜백은 동기식으로 작동한다. 데이터 흐름이 조금만 복잡해져도 코드가 복잡해진다는 문제가 생긴다.

  1. Promise 이것은 콜백자체를 하나의 통에 담는 방식이다.

⇒ 이를 통해서 가독력은 증가시키지만 결국에는 콜백이다. Promise는 콜백과 언젠가 끝나는 작업의 결과값을 담는 통이라고 할 수 있다. then 메소드를 통해 콜백을 등록하고, 작업이 끝났을 때 결과값을 가지고 추가 작업을 할 수 있다. then 메소드 자체도 Promise 객체를 반환할 수 있다. Promise의 진가는 복잡한 비동기 데이터 흐름을 다룰 때 발휘된다. 또한 비동기 작업 자체를 값으로 다룰 수 있게 된다. 결과값을 사용해 추가 작업을 하려면 then 메소드를 호출해야 한다.

  1. async, await 방식

⇒ 비동기 함수의 장점은 동기식 코드를 짜듯이 비동기식 코드를 짤 수 있다는 것이다.

  1. Generater

⇒ 이 함수는 '함수를 잠시 멈춰둘 수 있다' 라는 특징을 가지고 있습니다. 실제로 ES2017에서 비동기 함수가 도입되기 전까지 generater 가 비동기 프로그래밍에 널리 사용되었다고 합니다. React에서 Redux-Saga 역시 generater를 사용한다.

  • Promise객체는 세가지 상태를 가질 수 있다.
    1. pending - Promise 객체에 결과 값이 채워지지 않은 상태
    2. fulfilled - Promise 객체에 결과 값이 채워진 상태
    3. rejected - Promise 객체에 결과 값을 채우려다 실패한 상태

참고

https://asfirstalways.tistory.com/362

https://www.zerocho.com/category/JavaScript/post/597f34bbb428530018e8e6e2

https://helloworldjavascript.net/pages/285-async.html

https://velog.io/@jakeseo_me/2019-03-15-2303-작성됨-rmjta5a3xh

https://levelup.gitconnected.com/javascript-and-asynchronous-magic-bee537edc2da

반응형