일단 자바스크립트는 싱글스레드이다.
그렇기에 단 하나의 호출 스택(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된 다음 콜스택으로 들어가서 실행된다. 그러므로 이벤트에 걸려있는 핸들러는 절대 먼저 실행될 수 없다.
비동기 함수들을 내가 만든 함수를 등록시키기 위해서는 여러가지 방법이 존재하는데
- AJAX 방식으로 콜백을 등록시킨다.
⇒ 이 방식으로는 무한으로 콜백 함수가 붙어 이해하기가 어려운 콜백 헬이 발생하여 가독력이 떨어진다. 콜백은 동기식으로 작동한다. 데이터 흐름이 조금만 복잡해져도 코드가 복잡해진다는 문제가 생긴다.
- Promise 이것은 콜백자체를 하나의 통에 담는 방식이다.
⇒ 이를 통해서 가독력은 증가시키지만 결국에는 콜백이다. Promise는 콜백과 언젠가 끝나는 작업의 결과값을 담는 통이라고 할 수 있다. then 메소드를 통해 콜백을 등록하고, 작업이 끝났을 때 결과값을 가지고 추가 작업을 할 수 있다. then 메소드 자체도 Promise 객체를 반환할 수 있다. Promise의 진가는 복잡한 비동기 데이터 흐름을 다룰 때 발휘된다. 또한 비동기 작업 자체를 값으로 다룰 수 있게 된다. 결과값을 사용해 추가 작업을 하려면 then 메소드를 호출해야 한다.
- async, await 방식
⇒ 비동기 함수의 장점은 동기식 코드를 짜듯이 비동기식 코드를 짤 수 있다는 것이다.
- Generater
⇒ 이 함수는 '함수를 잠시 멈춰둘 수 있다' 라는 특징을 가지고 있습니다. 실제로 ES2017에서 비동기 함수가 도입되기 전까지 generater 가 비동기 프로그래밍에 널리 사용되었다고 합니다. React에서 Redux-Saga 역시 generater를 사용한다.
- Promise객체는 세가지 상태를 가질 수 있다.
- pending - Promise 객체에 결과 값이 채워지지 않은 상태
- fulfilled - Promise 객체에 결과 값이 채워진 상태
- 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
'개발 > Front-end' 카테고리의 다른 글
고급 개발자가 되는 길 (0) | 2024.08.29 |
---|---|
react-router-dom v6 무엇이 바뀌었는가? (2) | 2021.12.16 |
React 톺아보기를 보고 정리하기_1 (0) | 2021.08.11 |
TypeScript 하기 전에 이정도는 알아야지! (0) | 2021.07.05 |
Npm vs Yarn (0) | 2021.06.11 |