프로그래밍 언어가 구동되는 환경. Node.js나 크롬 등의 브라우저들은 자바스크립트가 구동되는 환경이기 때문에, Node.js나 브라우저들을 자바스크립트 런타임이라고 한다.
자바스크립트는 싱글 스레드, 논-블로킹 언어이다.
하나의 힙 영역과 하나의 콜 스택을 가진다.
- 한 번에 한 가지 일 밖에 하지 못한다는 의미.
- Ex) 네트워크 요청 => 응답이 올 때까지 기다릴 수 밖에 없음.
- ❗️ 힙 : 변수와 객체의 메모리 할당에 사용되는 비정형 메모리.
함수가 실행되는 순서를 기억한다.
- 함수를 실행하려면 스택의 가장 위에 해당 함수를 넣게 되고, 함수에서 리턴이 일어나면 스택의 가장 위쪽에서 함수를 꺼낸다.
싱글 스레드는 스택이 하나밖에 없기 때문에, 한 번에 한 가지 일 밖에 할 수 없다.
웹 브라우저에서 코드가 실행되는데, 코드가 종료될 때까지 유저가 클릭을 해도 어떠한 반응을 하지 않는 상태가 되버린다.
const fs = require('fs');
// 파일을 동기적으로 읽기
const data = fs.readFileSync('file.txt', 'utf8');
console.log(data);
console.log('파일 읽기가 완료되었습니다.');
위 예제는 파일을 동기적으로 읽으며 파일 읽기가 완료될 때까지 다음 코드로 진행하지 않는다.
블로킹 상태를 해결하는 방법
=> 논-블로킹, 비동기 콜백을 사용하는 것.
const fs = require('fs');
// 파일을 비동기적으로 읽기
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
console.log(data);
});
console.log('파일 읽기 요청을 보냈습니다.');
"파일 읽기 요청을 보냈습니다."
메시지가 먼저 출력되고, 파일 읽기가 완료된 후에 데이터가 출력된다.자바스크립트 런타임은 자바스크립트 엔진을 포함하고 있다. 크롬은
V8
을 자바스크립트 엔진으로 사용하고 있다.
구글에서 개발한 오픈소스 자바스크립트 엔진. C++로 만들어져 있으며, Node.js, 크롬 브라우저 등에서 사용된다.
V8은 싱글 스레드를 제공한다. 싱글 스레드는 하나의 콜 스택(Call Stack)과 하나의 힙(Heap)을 제공. 콜 스택은 위에서 이야기했듯이 함수의 호출 순서를 저장. 힙은 할당된 메모리들이 저장되는 영역.
그렇다면, V8 소스에는 이러한 메서드들이 정의되어 있지도 않는데,
setTimeut()
이나ajax
,DOM 이벤트
등 콜백으로 비동기 동작을 하는 코딩하는 것은 무엇일까?
setTimeout(..., 1000)
가 호출되었을 때, 어떤것이 1초를 카운트하고 1초 후에 콜백 함수를 실행시킬까? 바로 Web API 이다.setTimeout
이나 HTTP 요청 메서드
, DOM 이벤트
등의 메서드를 지원.setTimeout(cb, 1000)
을 호출하게 되면 Web API는 타이머를 동작시켜 1초 후에 콜백 큐에 cb를 쌓는다.setTimeout는 정확히 얼마 후 동작하겠다는 의미가 아니라 얼마 후 동작하는 최소 시간을 보장한다는 의미가 더 정확하다.
- 이유는?
정해진 시간 후 콜백이 콜백 큐에 쌓이는데, 콜백 큐에 쌓인 콜백이 콜 스택에 들어오기 위해서는 콜 스택이 비어 있어야 한다. 정해진 시간이 지난 후 그 이후에 콜 스택이 비어있을 때 setTimeout의 콜백이 실행된다.
function Test(){
console.log('하나');
setTimeout(()=> console.log('둘'), 0);
console.log('셋');
}
Test();
위의 예제에서 setTimeout(()=> console.log('둘'), 0)
의미는 0초 후 '둘'을 출력해줘 라는 의미이다. 그래서 Test()
함수를 호출했을 때에, '하나'
, '둘'
, '셋'
이 차례대로 출력될 것 같지만, 그렇지 않다. 실제 출력값은 '하나'
, '셋'
, '둘'
이다.
이유는 콜 스택이 비어있지 않기 때문.
ajax도 setTimeout과 동일하게 동작한다.
function foo(){
console.log('hi')
$.get('url', function cd(data){
console.log(data)
})
console.log('bye')
}
foo();
// Console
'hi'
'bye'
{ some : 'foo' }