개발 자료를 찾아보다 다음과 같은 질문을 발견 했는데, 깔끔하게 대답하지 못했다. 꼭 알고만 있어야 할 것 같은 질문처럼 보여서 공부하고 간략하게 정리했다.
① 여러 비동기 로직이 있을 때, 콘솔이 찍히는 순서를 설명하시오
② JavaScript에서 비동기 함수는 정확하게 3,000ms를 기다렸다가 실행이 되나요?
③ 만약 아니라면, 정확하게 3,000ms를 기다리게 할 수 있을까요? (Web API 관련 질문)
틀린 부분은 언제든지 고쳐주시면 감사하겠습니다 (꾸벅)
자바스크립트는 단일 스레드 언어로, 동기적 코드와 비동기적 코드를 이벤트 루프(Event Loop)를 통해 관리한다. 콘솔 로그의 출력 순서는 이 이벤트 루프의 동작 방식에 따라 결정된다.
console.log("Start");
setTimeout(() => {
console.log("Timeout");
}, 1000);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("End");
콘솔 출력 순서
"Start"
"End"
"Promise"
"Timeout"
Javascript의 동작 순서이다.
동기 코드의 실행
console.log("Start")와 console.log("End")는 동기적으로 즉시 실행
비동기 코드의 등록
setTimeout의 callback 함수는 Task Queue에 등록된다. 지정된 시간(여기서는 1000ms)이 지난 후 콜백이 태스크 큐에 추가된다. Promise.resolve().then(...)의 콜백은 Microtask Queue에 등록된다. 이미 resolve된 Promise이므로 .then의 callback이 즉시 마이크로태스크 큐에 추가된다. then의 callback이 비동기로 실행 될 것이다.
Event Loop 동작
Eventloop는 현재 실행중인 Task가 있는지, Queue들에 적재된 Task가 있는지 주기적으로 확인하고, 만약 실행중인 Task가 Call Stack에 없다면 Queue에서 Task를 꺼내와 Call Stack에 올리고 실행시키는 역할을 한다. Call stack을 확인 했더니 아무것도 없기 때문에 큐에 적재된 것을 처리한다.
Microtask Queue 처리
Microtask Queue가 Task Queue보다 우선순위가 높기 때문에 동기 코드 실행 후, Promise의 .then 콜백이 실행되어 "Promise"가 출력된다.
Task Queue 처리
1000ms가 지난 후, Call Stack이 비어 있기 때문에 등록된 setTimeout의 콜백이 실행되어 "Timeout"이 출력된다.
Event loop에 의해 Microtask Queue에 있는 콘솔이 출력되고 Task Queue에 있는 콘솔이 마저 출력된다.
*Animation Frames: 사용자가 스크롤을 이동하거나 화면을 갱신하는 것과 같이 브라우저 렌더링에 관련된 Task들이 담기는 Queue. 우선순위는 Microtask Queue와 TaskQueue의 중간.
결론부터 말하자면, 아니다.
setTimeout 함수는 지정한 시간이 지난 후 Callback 함수를 Task queue에 추가한다. 하지만 실제로 함수가 실행되는 시간은 다음과 같은 이유로 지연될 수 있다.
console.log("Start");
setTimeout(() => {
console.log("Executed after 0ms");
}, 0);
console.log("End");
결과
Start
End
Executed after 0ms
CPU 부하로 인한 지연
Copy code
console.log("Start");
setTimeout(() => {
console.log("Timeout after 100ms");
}, 100);
const heavyTask = () => {
const end = Date.now() + 500;
while (Date.now() < end) {
// 무거운 연산 수행 (예: 복잡한 계산)
}
console.log("Heavy task completed");
};
heavyTask()
예상 출력:
Start
Heavy task completed
Timeout after 100ms
메모리 부족으로 인한 지연
브라우저 상태의 영향(탭이 비활성화된 경우)
예시:
setInterval(() => {
console.log(`Interval executed at ${new Date().toLocaleTimeString()}`);
}, 500);
절전 모드 및 배터리 절약 모드
시스템 시간 조정의 영향
완벽하게 정확한 3,000ms 지연을 보장하기는 어렵지만, 타이머의 정확성을 높이기 위한 몇 가지 방법이 있다.
예시:
const largeArray = [...Array(1000000).keys()];
let index = 0;
function processChunk() {
const chunkSize = 1000;
const end = Math.min(index + chunkSize, largeArray.length);
for (; index < end; index++) {
// 데이터 처리
}
if (index < largeArray.length) {
setTimeout(processChunk, 0);
} else {
console.log("Processing complete");
}
}
processChunk();
예시:
main.js
const worker = new Worker('worker.js');
worker.onmessage = (event) => {
console.log(`Message from worker: ${event.data}`);
};
worker.js
setTimeout(() => {
postMessage('Timeout executed in worker');
}, 1000);
예시:
function preciseTimeout(callback, delay) {
const start = performance.now();
function check() {
const elapsed = performance.now() - start;
if (elapsed >= delay) {
callback();
} else {
requestAnimationFrame(check);
}
}
requestAnimationFrame(check);
}
preciseTimeout(() => {
console.log(`Precise timeout executed at ${performance.now()}ms`);
}, 3000);