--- title: WindowTimers.setTimeout() slug: Web/API/setTimeout tags: - setTimeout translation_of: Web/API/WindowOrWorkerGlobalScope/setTimeout original_slug: Web/API/WindowOrWorkerGlobalScope/setTimeout ---
타이머가 만료된 뒤 함수나 지정된 코드를 실행하는 타이머를 설정합니다.
var timeoutID = window.setTimeout(func[, delay, param1, param2, ...]); var timeoutID = window.setTimeout(code[, delay]); window.setTimeout(function, milliseconds);
func
code
delay
{{optional_inline}}param1, ..., paramN
{{optional_inline}}Internet Explorer 9 이하에서는 함수에 추가적인 매개변수들을 전달하는 기능이 동작하지 않습니다.
만약 브라우저에서 이 기능을 사용하고 싶다면, {{anch("polyfill")}}을 사용하세요. (Callback arguments를 봐주세요)
반환되는 timeoutID
는 숫자이고, setTimeout()
을 호출하여 만들어진 타이머를 식별할 수 있는 0이 아닌 값 입니다;
이 값은 타이머를 취소시키기 위해 {{domxref("WindowTimers.clearTimeout()")}}에 전달할 수도 있습니다.
setTimeout()과
{{domxref("WindowTimers.setInterval", "setInterval()")}}는 같은 ID 공간을 공유하기 때문에, clearTimeout()과
{{domxref("WindowTimers.clearInterval", "clearInterval()")}} 둘 중 어느 것을 사용해도 기술적으로 동일하게 동작합니다.
하지만 명확성을 위해, 코드를 유지보수할 때 혼란을 피하기 위해 항상 일치시켜야 합니다.
다음 예제는 웹 페이지에 2개의 간단한 버튼을 설정하고 setTimeout()과
clearTimeout()에 연결합니다
.
첫 번째 버튼이 눌려지면 2초 뒤에 호출되는 타임아웃이 설정되고 clearTimeout()
에 사용되는 ID가 저장됩니다.
두 번째 버튼을 누름으로써 당신은 선택적으로 이 타임아웃을 취소할 수 있습니다.
<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>
var timeoutID; function delayedAlert() { timeoutID = window.setTimeout(slowAlert, 2000); } function slowAlert() { alert("That was really slow!"); } function clearAlert() { window.clearTimeout(timeoutID); }
{{EmbedLiveSample('Example')}}
clearTimeout() 예제
도 봐주세요.
하나 이상의 매개변수를 콜백 함수에 넘겨야 하는데, 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'); }())
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은 {{domxref("WindowOrWorkerGlobalScope.clearTimeout()")}}을 사용하면 취소됩니다. 함수를 반복해서 호출해야 한다면 (e.g., N 밀리초마다), {{domxref("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은 문자열이 코드로 해석될 때 사용할 수 없습니다.
타임아웃이 예상보다 더 늦게까지 지연되는 데는 여러가지 이유가 있습니다. 이 문단에서는 일반적인 이유에 대해서 설명합니다.
역사적으로 브라우저들은 setTimeout()
"clamping"을 구현했습니다: "최소 지연" 한계보다 작은 지연을 가진 setTimeout() 호출은
최소 지연을 사용하도록 강제됩니다.
실제로, 4ms는 HTML5 스펙에 명시되어 있고 2010년 이후에 출시된 브라우저들은 일관성을 유지하고 있습니다. {{geckoRelease("5.0")}} 이전에 출시된 브라우저들은, 타임아웃(중첩 5이상)의 최소 지연시간은 10ms였습니다.
최신 브라우저에서 0ms 타임아웃을 구현하려면, 이곳에 설명된 {{domxref("window.postMessage()")}}를 사용할 수 있습니다.
부하와 배터리 사용양을 줄이기 위해서, 비활성화 탭들에서 타임아웃이 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보다 더 큰 지연을 사용할 때 정수 오버플로우가 발생하여, 타임아웃이 즉시 실행됩니다.
사양 | 상태 | 주석 |
---|---|---|
{{SpecName("HTML WHATWG", "webappapis.html#dom-settimeout", "WindowTimers.setTimeout()")}} | {{Spec2("HTML WHATWG")}} | Initial definition (DOM Level 0) |
{{Compat("api.WindowOrWorkerGlobalScope.setTimeout")}}