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);
};
위 2개의 대안들은 IE의 타이 콜백함수에 임의의 매개변수를 전달하는 HTML5 표준 또한 가능하게 합니다.

새로운 기능 테스트:

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
JavaScript 1.8.5은 주어진 함수에 대한 모든 호출의 this 값을 설정하기 위한 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보다 더 큰 지연을 사용할 때 정수 오버플로우가 발생하여, 타임아웃이 즉시 실행됩니다.

사양

사양 상태 주석
WHATWG 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에서 매개변수를 지원하는지에 대한 여부.

더 알아보기

문서 태그 및 공헌자

태그: 
 이 페이지의 공헌자: TroyTae
 최종 변경: TroyTae,