javascript

setTimeout에서 발생 가능한 문제들

하리하링웹 2024. 4. 21. 14:50

Settimeout

함수 설명

setTimeout(functionRef, delay, param1, param2, /* …, */ paramN)

첫 번째 인자에 넣은 함수를 딜레이 이후 실행해준다. 뒤의 파라미터들은 함수에 전달해주는 매개변수이다.

delay 값을 숫자값이 아니라 “1000” 과 같은식으로 전달할 경우 1초로 자동으로 변경된다. 잘못된 값을 넣으면 자동으로 0초로 변환된다.

반환 값은 timeoutID를 받으며 이는 clearTimeout() 을 통해 타입아웃을 취소할 수 있다.

This 문제

setTimeout은 다른 excution context에서 실행된다. 따라서 자바스크립트의 this 바인딩 특성상 이 값이 바뀔 수 있어 문제가 발생할 수 있다.

[정상 동작]

const myArray = ["zero", "one", "two"];
myArray.myMethod = function (sProperty) {
  console.log(arguments.length > 0 ? this[sProperty] : this);
};

myArray.myMethod(); // prints "zero,one,two"
myArray.myMethod(1); // prints "one"

위 코드의 경우 myMethod를 호출할 때 this가 myArray로 설정되어 정상적으로 동작한다.

setTimeout(myArray.myMethod, 1.0 * 1000); // 1초 후 "[object Window]" 기록
setTimeout(myArray.myMethod, 1.5 * 1000, "1"); // 1.5초 후 "undefined" 기록 (window["1"] === undefined) 

하지만 setTimeout의 경우 타임아웃 만료 시점에 this가 따로 설정되지 않아 기본값인 window 객체를 가리키게 되어 예상대로 동작하지 않는다.

이러한 문제는 클로저, bind() 를 통해 해결할 수 있다.

Delay가 부정확한 문제

  • setTimeout 호출이 5번 이상 중첩된경우 최소 4ms의 지연을 준다.
let start = Date.now();
let times = [];

setTimeout(function run() {
  times.push(Date.now() - start); 

  if (start + 100 < Date.now()) {
    console.log(times)
    return
  }
  setTimeout(run); 
});

// 출력 [1, 1, 1, 1, 9, 14, 18, 23, 27...

setInterval에도 동일하게 적용된다.

이러한 제약은 브라우저에서만 존재하며 서버에서는 process.nextTick, setImmediate사용을 통해 지연 없이 실행할 수 있다.

  • 백그라운드에서의 지연

백그라운드에서의 부하를 경감하기 위해 브라우저는 비활성 탭에 지연 시간을 강제로 부여한다. (브라우저 마다 다름)

단 소리를 재생중일 때에는 지연을 강제하지 않는 경우도 있다.

  • 사용자 추적 스크립트에 대한 쓰로틀링 적용

소셜 네트워크같은곳에서 사용하는 사용자의 방문기록, 행동등을 기록하는 스크립트라고 인식하였을 때 백그라운드라면 이러한 스크립트에 대해 첫 로드 이후 30초가 지났을 때 10초의 쓰로틀링을 적용한다. (브라우저 마다 다름)

  • callStack이 비어있지 않을 경우
function foo() {
  console.log("foo 호출");
}
setTimeout(foo, 0);
console.log("setTimeout 완료");

//setTimeout 완료
//foo 호출
  • webExtension의 경우

extension의 setTimeout은 신뢰할 수 없기때문에 extension에서는 alarms API 사용을 권장하고 있다.

  • 최대 지연시간을 초과한 경우

브라우저들에서 내부적으로 32비트의 정수 값으로 지연 시간을 저장한다. 따라서 2,147,483,647ms(약 24.8일) 초과의 값을 지정할 경우 오버플로우가 발생해 타입아웃이 즉시 만료된다.

  • 페이지 로드 중 타임아웃 지연

현재 탭이 로드 중일 때 타이머를 지연하는 브라우저도 있다.