자바스크립트의 setTimeout 함수는 특정 작업을 지정된 시간 후에 실행하도록 예약하는 데 사용됩니다. 하지만 의도와는 다르게 setTimeout의 실행 시간을 정확하게 보장할 수는 없습니다. 그 이유는 자바스크립트의 이벤트 루프와 싱글 스레드의 작동 방식과 관련이 있습니다.
setTimeout 예시
function printPerformanceNow() {
console.log(`${performance.now().toFixed(0)}ms`);
}
function myCallback() {
console.log(`setTimeout 실행 시간`);
printPerformanceNow();
}
console.log(`실제 실행 시간`);
printPerformanceNow();
// 1초 후에 콜백 함수 실행
setTimeout(myCallback, 1000);
printPerformanceNow();
실제로 setTimout이 실행되는 타이밍을 알기위해서 위 와 같은 코드를 실행시켜보겠습니다.
결과는 위와 같습니다. 의도한대로 코드가 실행되고 1초 뒤에 setTimeout의 callBack 함수가 실행되었습니다. 여기에 추가로 오래 걸리는 연산을 추가해보겠습니다. 예를 들면 2중 루프를 실행해보죠.
console.log(`실제 실행 시간`);
printPerformanceNow();
// 1초 후에 콜백 함수 실행
setTimeout(myCallback, 1000);
// 지연을 위한 더미 작업
for (let i = 0; i < 100000; i++) {
for (let j = 0; j < 100000; j++) { }
}
console.log(`for 문 종료 시간`);
printPerformanceNow();
위 코드에서 setTimeout 코드 이후에
// 지연을 위한 더미 작업
for (let i = 0; i < 100000; i++) {
for (let j = 0; j < 100000; j++) { }
}
위 코드를 추가 했습니다.
결과를 확인해보겠습니다.
setTimout 의 콜백이 1초 뒤에 실행되기를 기도했던것과는 달리 추가한 for문의 연산이 모두 종료될때까지 setTimout 의 콜백이 실행되지 않습니다.
자바스크립트는 왜 이 모양인걸까요?
setTimeout 이러는 이유가 있을거 아니에요?
1. 이벤트 루프(Event Loop)와 비동기 작업
자바스크립트는 싱글 스레드로 동작하는 언어입니다. 이는 한 번에 하나의 작업만 처리할 수 있음을 의미합니다. 따라서 시간이 오래 걸리는 작업을 하게 되면 다른 작업들이 차단될 수 있습니다. 이를 방지하기 위해 비동기적으로 작업을 처리합니다.
setTimeout 함수는 비동기적으로 동작합니다. 즉, 실행해야 하는 코드를 호출 스택에서 제거하고, 특정 시간이 지난 후에 콜백 함수를 태스크 큐로 이동시킵니다. 이벤트 루프는 계속해서 호출 스택과 태스크 큐를 모니터링하며, 호출 스택이 비어있을 때 태스크 큐에서 작업을 꺼내와 실행합니다.
2. 타이머의 정확성
setTimeout의 실행 시간은 정확하게 보장되지 않습니다. 여러 요소들이 실행 시간을 영향을 줄 수 있습니다:
타이머의 지연
setTimeout의 지연 시간은 최소한으로 지정될 수 있지만, 실행 시간은 그 후로 늦어질 수 있습니다. 특히 브라우저나 컴퓨터 자원의 사용량이 많을 경우 지연이 발생할 가능성이 큽니다.
브라우저/환경 종속성
브라우저나 실행 환경마다 setTimeout의 동작 방식이 약간씩 다를 수 있습니다. 따라서 다른 환경에서 같은 코드가 실행될 때 결과가 조금씩 달라질 수 있습니다.
( 브라우저 동작에 관련해서는 MDN 페이지를 참고하면 좋습니다. )
인터럽트
JavaScript가 실행 중에 다른 이벤트가 발생하면 인터럽트가 발생할 수 있습니다. 예를 들어, 마우스 클릭이나 키보드 입력과 같은 이벤트가 발생하면 이벤트 핸들러가 먼저 실행되어 타이머가 지연될 수 있습니다.
최소 타이머 정밀도
setTimeout은 대개 최소 타이머 정밀도에 의해 설정된 시간보다 조금 더 느릴 수 있습니다. 이는 특정 환경에서 더욱 두드러질 수 있으며, 이는 실행 시간의 정확성에 영향을 줄 수 있습니다.
결론
정리하면 자바스크립트는 싱글스레드이기 때문에 호출 스택이 모두 비어야 태스크 큐에 있는 setTimeout 함수를 꺼내와서 실행하게 됩니다. 앞서 예시처럼 오래걸리는 연산이 종료되어야 호출 스택이 텅비게 됩니다. 그래서 setTimeout은 연산이 모두 종료될때까지 기다리고 실행되는것이죠.
setTimeout을 사용할 때는 실행 시간의 정확성을 보장받기 어렵다는 것을 알아두고 타이밍은 최소한의 지연시간으로 이해하는것이 중요합니다. 이는 자바스크립트의 모든 비동기 타이밍 함수들에 공통으로 적용됩니다.
따라서 시간에 민감한 작업을 처리해야 하는 경우에는 다른 방법을 고려해야 합니다. 예를 들어, requestAnimationFrame을 사용하여 브라우저의 다음 리페인트 주기 전에 작업을 실행하는 것이 정확성 측면에서 더욱 안정적일 수 있습니다. 또는 실시간 작업을 처리해야 하는 경우에는 Web Workers를 고려해볼 수도 있습니다.
'개발관련 > 자바스크립트 팁' 카테고리의 다른 글
javascript fetch response body가 null인 경우 처리 하는 방법. (0) | 2024.03.07 |
---|---|
타입스크립트는 왜 Object.keys의 타입을 모를까 (0) | 2023.08.20 |
자바스크립트 parseInt / parseFloat / number를 이용하지 않고 문자열을 숫자로 형변환 하는 구현 방법 (0) | 2023.07.11 |
자바스크립트를 예로 들어서 의존성 역전 원칙(Dependency Inversion Principle, DIP) (0) | 2023.07.10 |
자바스크립트의 실행 컨텍스트, Lexical Environment 및 관련 컨셉 이해하기 (0) | 2023.05.18 |