자바스크립트는 하나의 콜 스택을 가지는 싱글 스레드 프로그래밍 언어이다. 싱글 스레드라는 것은 한 번에 하나의 명령 집합만이 실행된다는 것을 의미한다. 그렇기 때문에 자바스크립트는 동기식(Synchronous)으로 작업을 처리할 수 밖에 없는데 , 이로 인해서 많은 문제가 발생한다.
만약 처리하는데 많은 시간이 걸리는 작업이 있다고 생각해보자. 그 작업이 실행되는 동안 사용자는 아무것도 할 수 없을 것이다.
개발자 도구를 열고 콘솔창에 alert("text")
을 입력해 보자.
메시지가 떠있는 동안에는 스크롤 할 수도 , 다른 버튼을 클릭 할 수도 없다. 이렇듯 시간이 아주 많이 걸리는 작업이 콜 스택에서 빠져나가지 못하고 계속 처리한다면 사용자는 어떠한 일도 할 수 없을 것이다.
앞에서 언급했듯 자바스크립트 엔진에는 하나의 메모리 힙과 콜 스택이 존재하므로 다른 프로그램이 무언가를 실행하려면 현재 작업이 끝날때 까지 기다려야하는 문제점이 있었다. 그리고 만약 많은 시간이 걸리는 작업을 수행한다면 프로그램이 엄청나게 느려질 것이다.
그렇다면 어떠한 방식이 이를 해결할 수 있을까?
오래 걸리는 일은 백그라운드에서 처리하고 간단하게 처리할 수 있는 작업들만 콜 스택에서 수행한다면 효율적으로 처리할 수 있을것이다. 그리고 이런 일이 가능하게 해주는 것이 바로 자바스크립트 런타임 이다.
Web API는 브라우저와 함께 제공된다. 웹 API는 HTTP 전송, setTimeout , DOM Event 등과 같은 다양한 작업을 수행할 수 있다. 또한 브라우저에서 캐싱 또는 데이터베이스 저장소를 사용할 수 있게 해준다.
개발자 도구에 들어가서 콘솔창에 window
를 입력해 보자.
엄청나게 방대한 양의 객체가 나오는 것을 확인할 수 있는데 이 window
객체가 바로 브라우저가 제공하는 Web API 이다. 간단하게 몇가지 요소들만 살펴보자.
스크롤 하다보면 HTTP 호출을 하기 위해서 사용되는 fetch
함수 를 발견할 수 있고, 이는 사용자가 직접 사용이 가능하다.
indexedDB
는 브라우저에서 사용할 수 있는 작은 데이터베이스이다.
참고로 이는 Application
탭에 들어가서 확인이 가능하다.
마지막으로는 평소에도 예제에 자주 사용되는 setInterval
과 setTimeout
을 확인할 수 있는데 이 또한 마찬가지로 브라우저에서 제공되는 Web API이다.
위와 같은 함수들은 동기적으로 처리할 경우 심각하게 느려지거나 아예 먹통이 될 수 있는 함수들이다. 그러므로 백그라운드에서 처리하기 위해서 Web API로 따로 빼놓고 사용하는 것이라고 유추해 볼 수 있다 (뇌피셜)
어찌됐건 결론은 Web API를 사용하여 백그라운드에서 비동기적으로 작업을 처리할 수 있고 , 이러한 작업이 끝나면 자바스크립트 엔진(콜 스택)에게 해당 작업이 끝났음을 알려주어 계속해서 작업을 수행해 나갈 수 있게 된다.
Web API는 브라우저에서 제공되는 함수 및 기타 등등이라고 배웠다. 예를 들어, 코드를 쭉 실행하다가 setInterval
함수가 나온다면 콜 스택은 '이건 내가 모르는건데?' 하고 Web API로 전달한다.
Web API에서는 해당 작업을 자체적으로 처리한 뒤 콜백 큐(Callback Queue) 로 전달한다. 이렇게 콜백 큐로 들어온 작업들은 콜 스택이 비어있을 경우에만 콜 스택으로 이동하게 되는데 이 때 이벤트 루프(Event Loop) 가 콜 스택이 비어있는지 주기적으로 확인하고 콜백 큐에 있는 작업들을 이동시키는 역할을 한다.
말로 설명하면 어려우니까 예제를 보고 이해해보자.
function d(){
console.log("Hello")
}
function c(){
setTimeout(d , 3000);
}
function b() {
c();
}
function a() {
b();
}
a();
a 함수는 b를 호출하고 b 함수는 c 를 , c함수는 setTimeout(d , 3000)
을 수행한다. 그리고 마지막으로는 d 함수에서 console.log("Hello")
를 수행한다.
setTimeout(d,3000)
함수를 콜 스택에서 Web API로 이동시킨다.setTimeout(d,3000)
를 수행한다.d
를 콜 스택으로 이동시킨다.d
를 수행하고 console.log("Hello")
를 수행한다.그렇다면 만약 setTimeout(d,0)
으로 바꾼다면 결과가 달라질까? 한 번 알아보자.
Web API 에서 바로 콜백 큐로 이동했지만 콜 스택이 비어있기 전에 작업이 이동되지 않는것을 확인할 수 있다 .