WindowTimers.setTimeout()
타이머가 만료된 뒤 함수나 지정된 코드를 실행하는 타이머를 설정합니다.
문법
var timeoutID = window.setTimeout(func[, delay, param1, param2, ...]); var timeoutID = window.setTimeout(code[, delay]); window.setTimeout(function, milliseconds);
매개변수
func
function
이 타이머가 만료된 뒤 실행됩니다.code
- 선택적 구문으로 함수 대신에 문자열을 넣을 수 있는데, 이것은 타이머가 만료된 뒤 해석되고 실행됩니다.
이 구문은eval()
을 사용하는 것과 같은 보안 위험성을 이유로 권장되지 않습니다. delay
Optional- 타이머가 지정된 함수나 코드를 실행시키기 전에 기다려야할 ms(1000분의 1초) 단위의 시간입니다.
만약 이 매개변수를 생략하면, 0이 값으로 사용됩니다. 실제 지연시간은 더 길어질 수 있습니다;
아래 Reasons for delays longer than specified를 참고하세요. param1, ..., paramN
Optional- 타이머가 만료되고 func에 전달되는 추가적인 매개변수들입니다.
Internet Explorer 9 이하에서는 함수에 추가적인 매개변수들을 전달하는 기능이 동작하지 않습니다.
만약 브라우저에서 이 기능을 사용하고 싶다면, polyfill을 사용하세요. (Callback arguments를 봐주세요)
반환 값
반환되는 timeoutID
는 숫자이고, setTimeout()
을 호출하여 만들어진 타이머를 식별할 수 있는 0이 아닌 값 입니다;
이 값은 타이머를 취소시키기 위해 WindowTimers.clearTimeout()
에 전달할 수도 있습니다.
setTimeout()과
setInterval()
는 같은 ID 공간을 공유하기 때문에, clearTimeout()과
clearInterval()
둘 중 어느 것을 사용해도 기술적으로 동일하게 동작합니다.
하지만 명확성을 위해, 코드를 유지보수할 때 혼란을 피하기 위해 항상 일치시켜야 합니다.
예제
다음 예제는 웹 페이지에 2개의 간단한 버튼을 설정하고 setTimeout()과
clearTimeout()에 연결합니다
.
첫 번째 버튼이 눌려지면 2초 뒤에 호출되는 타임아웃이 설정되고 clearTimeout()
에 사용되는 ID가 저장됩니다.
두 번째 버튼을 누름으로써 당신은 선택적으로 이 타임아웃을 취소할 수 있습니다.
HTML
<p>Live Example</p>
<button onclick="delayedAlert();">Show an alert box after two seconds</button>
<p></p>
<button onclick="clearAlert();">Cancel alert before it happens</button>
JavaScript
var timeoutID;
function delayedAlert() {
timeoutID = window.setTimeout(slowAlert, 2000);
}
function slowAlert() {
alert("That was really slow!");
}
function clearAlert() {
window.clearTimeout(timeoutID);
}
결과
clearTimeout() 예제
도 봐주세요.
Polyfill
하나 이상의 매개변수를 콜백 함수에 넘겨야 하는데, setTimeout()
또는 setInterval()
을 사용하여 추가적인 매개변수를 보내는 것을 브라우저에서 지원하지 않는다면(e.g.
Internet Explorer 9 이하)
, HTML5 표준 매개변수 전달 기능을 사용 가능하게 하는 이 polyfill을 넣을 수 있습니다. 그저 아래 코드를 스크립트를 상단에 작성해주시면 됩니다.
/*\
|*|
|*| 임의의 매개변수를 자바스크립트 타이머의 콜백함수에 전달하기 위한 Polyfill (HTML5 표준 명세).
|*|
|*| https://developer.mozilla.org/en-US/docs/DOM/window.setInterval
|*|
|*| Syntax:
|*| var timeoutID = window.setTimeout(func, delay[, param1, param2, ...]);
|*| var timeoutID = window.setTimeout(code, delay);
|*| var intervalID = window.setInterval(func, delay[, param1, param2, ...]);
|*| var intervalID = window.setInterval(code, delay);
|*|
\*/
(function() {
setTimeout(function(arg1) {
if (arg1 === 'test') {
// feature test is passed, no need for polyfill
return;
}
var __nativeST__ = window.setTimeout;
window.setTimeout = function(vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */ ) {
var aArgs = Array.prototype.slice.call(arguments, 2);
return __nativeST__(vCallback instanceof Function ? function() {
vCallback.apply(null, aArgs);
} : vCallback, nDelay);
};
}, 0, 'test');
var interval = setInterval(function(arg1) {
clearInterval(interval);
if (arg1 === 'test') {
// feature test is passed, no need for polyfill
return;
}
var __nativeSI__ = window.setInterval;
window.setInterval = function(vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */ ) {
var aArgs = Array.prototype.slice.call(arguments, 2);
return __nativeSI__(vCallback instanceof Function ? function() {
vCallback.apply(null, aArgs);
} : vCallback, nDelay);
};
}, 0, 'test');
}())
IE
IE9 이하를 포함하는 모든 모바일/데스크톱 브라우저에서 자바스크립트를 남용하지 않는 완벽한 해결책으로 , JavaScript 조건부 주석을 사용할 수 있습니다:
/*@cc_on
// conditional IE < 9 only fix
@if (@_jscript_version <= 9)
(function(f){
window.setTimeout=f(window.setTimeout);
window.setInterval=f(window.setInterval);
})(function(f){return function(c,t){var a=[].slice.call(arguments,2);return f(function(){c instanceof Function?c.apply(this,a):eval(c)},t)}});
@end
@*/
혹은 IE HTML 조건부 기능을 기반으로 깔끔하게 접근할 수 있습니다:
<!--[if lte IE 9]><script>
(function(f){
window.setTimeout=f(window.setTimeout);
window.setInterval=f(window.setInterval);
})(function(f){return function(c,t){
var a=[].slice.call(arguments,2);return f(function(){c instanceof Function?c.apply(this,a):eval(c)},t)}
});
</script><![endif]-->
예시
다른 해결책으로는 익명 함수를 callback으로 호출하여 사용할 수 있으나, 이 방법은 비용이 더 비쌉니다.
var intervalID = setTimeout(function() { myFunc("one", "two", "three"); }, 1000);
위 예제는 arrow function으로도 작성하실 수 있습니다.
var intervalID = setTimeout(() => { myFunc("one", "two", "three"); }, 1000);
다른 하나는 function's bind
를 이용하는 것 입니다.
setTimeout(function(arg1){}.bind(undefined, 10), 1000);
"this
" 문제
setTimeout()
에 매개변수(혹은 다른 함수)를 전달할 때, 당신의 기대와는 다르게 this의 값이 호출될 것이다. 해당 이슈에 대한 자세한 사항은 JavaScript reference를 참고해주세요.
설명
setTimeout()
에 의해 실행된 코드는 별도의 실행 컨텍스트에서 setTimeout
이 호출된 함수로 호출됩니다. 호출된 함수에 대해서는 this
키워드를 설정하는 일반적인 규칙이 적용되며, this를 설정 혹은 할당하지 않은 경우, non-strict 모드에서 전역(혹은 window
) 객체, strict모드에서 undefined를 기본 값으로 합니다. 다음 예제를 봐주세요:
myArray = ["zero", "one", "two"];
myArray.myMethod = function (sProperty) {
alert(arguments.length > 0 ? this[sProperty] : this);
};
myArray.myMethod(); // prints "zero,one,two"
myArray.myMethod(1); // prints "one"
위와 같이 동작하는 이유는 myMethod
호출될 때, this
는 myArray
로 설정되므로, 함수 내에서의 this[
속성]
은 myArray[
속성]
와 같습니다. 하지만, 다음 예제를 보면:
setTimeout(myArray.myMethod, 1000); // 1초 뒤 "[Window 객체]" 출력
setTimeout(myArray.myMethod, 1500, "1"); // 1.5초 뒤 "undefined" 출력
myArray.myMethod
함수는 setTimeout
에 전달되고, 호출될 때 this
는 설정되어 있지 않아 window 객체를 기본값으로 합니다. forEach, reduce 등 Array 메서드 같이 this
를 매개변수로 넘길 수 있는 옵션 또한 없습니다. 그리고 아래에서 보다시피, call을
사용해 this
를 설정하는 것도 동작하지 않습니다.
setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object"
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error
가능한 해결책
일반적인 해결책은 this 설정이 필요한 곳을 함수로 감싸는 것(Wrapper Function) 입니다:
setTimeout(function(){myArray.myMethod()}, 2000); // 2초 뒤"zero,one,two" 출력
setTimeout(function(){myArray.myMethod('1')}, 2500); // 2.5초 뒤"one" 출력
화살표 함수(Arrow Function) 역시 가능한 대안입니다:
setTimeout(() => {myArray.myMethod()}, 2000); // 2초 뒤 "zero,one,two" 출력
setTimeout(() => {myArray.myMethod('1')}, 2500); // 2.5초 뒤 "one" after 2.5 출력
this
문제를 해결하는 또다른 방법은 전역함수 setTimeout()과
setInterval()를
this
객체를 전달할 수 있는 전역함수로 대체하고 Function.prototype.call
을 사용하여 콜백을 설정합니다:
// Enable setting 'this' in JavaScript timers
var __nativeST__ = window.setTimeout,
__nativeSI__ = window.setInterval;
window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
var oThis = this,
aArgs = Array.prototype.slice.call(arguments, 2);
return __nativeST__(vCallback instanceof Function ? function () {
vCallback.apply(oThis, aArgs);
} : vCallback, nDelay);
};
window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
var oThis = this,
aArgs = Array.prototype.slice.call(arguments, 2);
return __nativeSI__(vCallback instanceof Function ? function () {
vCallback.apply(oThis, aArgs);
} : vCallback, nDelay);
};
새로운 기능 테스트:
myArray = ["zero", "one", "two"];
myArray.myMethod = function (sProperty) {
alert(arguments.length > 0 ? this[sProperty] : this);
};
setTimeout(alert, 1500, "Hello world!"); // the standard use of setTimeout and setInterval is preserved, but...
setTimeout.call(myArray, myArray.myMethod, 2000); // prints "zero,one,two" after 2 seconds
setTimeout.call(myArray, myArray.myMethod, 2500, 2); // prints "two" after 2.5 seconds
Function.prototype.bind()
메서드를 도입하였습니다. 이렇게 하면 wrapper 함수를 사용하지 않고 콜백에 this 값을 설정할 수 있습니다.bind()
를 사용한 예제:
myArray = ["zero", "one", "two"];
myBoundMethod = (function (sProperty) {
console.log(arguments.length > 0 ? this[sProperty] : this);
}).bind(myArray);
myBoundMethod(); // prints "zero,one,two" because 'this' is bound to myArray in the function
myBoundMethod(1); // prints "one"
setTimeout(myBoundMethod, 1000); // still prints "zero,one,two" after 1 second because of the binding
setTimeout(myBoundMethod, 1500, "1"); // prints "one" after 1.5 seconds
참고
Timeout은 WindowOrWorkerGlobalScope.clearTimeout()
을 사용하면 취소됩니다. 함수를 반복해서 호출해야 한다면 (e.g., N 밀리초마다), WindowOrWorkerGlobalScope.setInterval()
사용을 고려해보세요.
setTimeout()을
호출한 쓰레드가 종료될 때까지 함수나 코드 조각이 실행될 수 없다는 점에 유의해야합니다. 예를들어:
function foo(){
console.log('foo has been called');
}
setTimeout(foo, 0);
console.log('After setTimeout');
콘솔에 이렇게 쓰여질겁니다:
After setTimeout
foo has been called
그 이유는 setTimeout가 지연시간 0으로
호출되었지만, queue에 배치되어 다음 기회에 실행되도록 예정되기 때문입니다. 현재 실행중인 코드는 queue에 있는 함수들이 실행되기 전에 완료되고, 실행 순서가 예상과 다를 수 있습니다.
문자열을 넘길경우
setTimeout()
에
함수대신 문자열을 넘기면 eval
사용했을 때와 같은 위험성을 가집니다.
// 권장
window.setTimeout(function() {
alert("Hello World!");
}, 500);
// 비권장
window.setTimeout("alert('Hello World!');", 500);
setTimeout
에 전달된 문자열은 전역 context에서 해석하므로, setTimeout()
이 호출된 로컬 context의 Symbol은 문자열이 코드로 해석될 때 사용할 수 없습니다.
지정된 것보다 더 오래 지연되는 이유
타임아웃이 예상보다 더 늦게까지 지연되는 데는 여러가지 이유가 있습니다. 이 문단에서는 일반적인 이유에 대해서 설명합니다.
중첩된 타임아웃이 4ms 이하일 경우
역사적으로 브라우저들은 setTimeout()
"clamping"을 구현했습니다: "최소 지연" 한계보다 작은 지연을 가진 setTimeout() 호출은
최소 지연을 사용하도록 강제됩니다.
실제로, 4ms는 HTML5 스펙에 명시되어 있고 2010년 이후에 출시된 브라우저들은 일관성을 유지하고 있습니다. (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) 이전에 출시된 브라우저들은, 타임아웃(중첩 5이상)의 최소 지연시간은 10ms였습니다.
최신 브라우저에서 0ms 타임아웃을 구현하려면, 이곳에 설명된 window.postMessage()
를 사용할 수 있습니다.
비활성 탭에서 타임아웃이1000ms에 여러 번 일어날 경우
부하와 배터리 사용양을 줄이기 위해서, 비활성화 탭들에서 타임아웃이 1초에 여러번 일어나지 않도록 "clamping" 됩니다.
Firefox는 5버전부터 이 동작을 구현했습니다. (bug 633421참고, 1000ms 상수는 dom.min_background_timeout_value
설정을 통해 수정할 수 있습니다)
Chrome은 11버전부터 구현했습니다 (crbug.com/66078).
Android용 Firefox는 bug 736602 이후 버전 14부터 백그라운드 탭에 15분의 타임아웃을 사용하고, 완전히 unload도 할 수 있습니다.
타임아웃 지연
"clamping"과 더불어, 타임아웃은 다른 작업들로 인해 바쁜 페이지에서 늦게 실행될 수 있습니다.
최대 지연 값
Internet Explorer, Chrome, Safari, and Firefox 포함하는 브라우저들은 내부적으로 32-bit 부호있는 정수로 지연 값을 저장합니다. 이로 인해 2147483647보다 더 큰 지연을 사용할 때 정수 오버플로우가 발생하여, 타임아웃이 즉시 실행됩니다.
사양
사양 | 상태 | 주석 |
---|---|---|
HTML Living Standard The definition of 'WindowTimers.setTimeout()' in that specification. |
Living Standard | Initial definition (DOM Level 0) |
지원 브라우저
기능 | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
기본 | 1.0 | 1.0 (1.7 or earlier) | 4.0 | 4.0 | 1.0 |
Callback 매개변수 지원[1] | (Yes) | (Yes) | 10.0 | (Yes) | (Yes) |
기능 | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
기본 | 1.0 | 1.0 | 1.0 (1) | 6.0 | 6.0 | 1.0 |
Callback 매개변수 지원[1] | ? | ? | ? | ? | ? | ? |
[1] 첫번째 form에서 매개변수를 지원하는지에 대한 여부.