대규모 프로젝트, 게임서버보다는 Restful API, 채팅 PUSH 서버에 적합
function run() {
console.log('동작');
}
console.log('시작');
setTimeout(run, 3000);
console.log('끝');
위 코드의 출력 결과는
시작
끝
동작
호출스택에서는 전역 컨텍스트인 main()이 쌓이고 console.log('시작')이 쌓입니다.
console.log('시작')함수가 호출되며 호출스택에서 빠집니다.('시작' 출력)
setTimeout이 호출되고 지워지면서 백그라운드로 run 함수와 함께 3초 타이머를 보냅니다. 백그라운드는 3초를 센 후 태스크 큐에 run 함수를 보냅니다.
그리고 console.log('끝')이 호출스택에 쌓엿다가 끝이 호출되면서 지워집니다.
그리고 마지막으로 main()이 사라지며 호출 스택이 비워지게 됩니다.
이벤트 루프는 항상 대기하고 있다가 호출 스택이 비워지면(전역 컨텍스트 main 실행이 종료되면) 태스크 큐에서 함수를 하나씩 호출 스택으로 밀어 올립니다.
이제 run 함수가 실행되고 호출 스택에서 지워지게 됩니다. 이벤트루프는 태스크 큐에 새로운 함수가 들어올 때까지 대기합니다.
출처 : (JavaScript) 호출 스택과 이벤트루프
동기 vs 비동기 : 호출되는 함수의 작업 완료 여부를 누가 신경쓰느냐
블로킹 vs 논블로킹 : 호출되는 함수가 바로 return하느냐 마느냐
const fs = require('fs');
const data = fs.readFileSync('/file.md'); // 파일을 읽을 때까지 여기서 블로킹됩니다.
console.log(data);
// moreWork();는 console.log 이후 실행될 것입니다.
const fs = require('fs');
fs.readFile('/file.md', (err, data) => { //논블록킹
if (err) throw err;
console.log(data);
});
// moreWork();는 console.log 이전에 실행될 것입니다.
//fs.readFile()가 논블로킹이므로
//계속 JavaScript를 실행하고
//moreWork()가 먼저 호출될 것입니다.
//파일 읽기가 완료되기를 기다리지 않고 moreWork()를 실행
-결과를 돌릴 때마다 나오는 순서가 달라진다, 결과가 나오는 순서를 제어하지 못한다.
해결방법 : promise / async,await
new Promise(function(resolve, reject){
setTimeout(function() {
resolve(1);
}, 2000);
})
.then(function(result) {
console.log(result); // 1
return result + 10;//10+1을 다음 then의 result로 넘겨줌
})
.then(function(result) {
console.log(result); // 11
return result + 20;
})
.then(function(result) {
console.log(result); // 31
});
위 코드는 프로미스 객체를 하나 생성하고 setTimeout()
을 이용해 2초 후에 resolve()
를 호출하는 예제입니다.
resolve()
가 호출되면 프로미스가 대기 상태에서 이행 상태로 넘어가기 때문에 첫 번째 .then()
의 로직으로 넘어갑니다. 첫 번째 .then()
에서는 이행된 결과 값 1을 받아서 10을 더한 후 그다음 .then()
으로 넘겨줍니다. 두 번째 .then()
에서도 마찬가지로 바로 이전 프로미스의 결과 값 11을 받아서 20을 더하고 다음 .then()
으로 넘겨줍니다. 마지막 .then()
에서 최종 결과 값 31을 출력합니다.
출력결과
func1 hello
func1
func2 world
func2
출처 : sopt 동아리 ppt
Node.js에서 JavaScript 실행이 싱글 스레드(이벤트 루프와 같은 스레드)에서 동작한다.
따라서 Node.js의 동시성은 다른 작업이 완료된 후에 JavaScript 콜백 함수를 실행하는 이벤트 루프의 능력(수용량)을 의미한다. 즉, javascript 실행은 하나의 이벤트 루프에서만 동작하지만 이벤트 루프의 여러 콜백 함수를 실행하여 동시에 처리되도록 보이는 것을 의미한다.
따라서 동시성을 높이기 위해 동시에 실행시킬 코드는 I/O와 같은 non-Javascript 연산이 일어날 때, 이벤트 루프가 계속 실행되도록 해주는 것이 좋다.
예를 들어 웹 서버에 대한 각 요청을 수행하는데 50ms가 걸릴 때 database I/O가 45ms 걸리고, 비동기적으로 처리한다고 생각하보자. 이렇게 non-blocking 비동기 연산 방식이기 때문에 45ms 동안 다른 일을 할 수 있게 되고 따라서 그 동안에 다른 요청을 처리할 수 있다. 이 점 때문에 blocking 함수 대신 non-blocking 함수를 사용하게 되면 더 많은 요청을 처리할 수 있다.
출처