- setTimout이 의도와 다르게 동작하는 것은 브라우저의 정책 때문이다.
https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#reasons_for_delays_longer_than_specified
부하를 줄이기 위해서 탭이 inactive 될 때 delay 시간을 강제로 늘린다.
Firefox Desktop and Chrome both have a minimum timeout of 1 second for inactive tabs.
- 이 문제를 해결하기 위해 'Web Worker'를 사용해보기로 한다. web worker는 독립된 thread에서 스크립트를 실행하기 때문에, inactive tab에서도 setTimeout이 원하는 타이밍에 동작한다.
- 아래는 setTimeout을 이용한 기존 로직이다. delay 시간 후 함수를 실행하고자 한다.
// example.tsx
useEffect(() => {
const listener = setTimeout(() => {
...함수 실행...
}, delay);
return () => {
clearTimeout(listener);
};
, [...]);
- setTimeout을 대신 실행해 줄 worker script를 작성한다.
// workers/setTimeout.js
onmessage = function (e) {
let delay = e.data;
let timer = setTimeout(() => {
postMessage(null);
clearTimeout(timer);
}, delay);
};
delay를 parameter(e.data)로 받고, delay 시간 후 다시 'main script'(worker를 호출한 스크립트)에게 Message를 보내서(postMessage) setTimeout이 동작했음을 알린다.
- 이제 이 워커를 main script에 적용한다. 아래는 웹워커를 적용한 코드이다.
// example.tsx
useEffect(() => {
const myWorker = new Worker('workers/setTimeout.js');
myWorker.postMessage(delay);
myWorker.onmessage = function () {
...함수 실행...
};
return () => {
myWorker.terminate();
};
}, []);
- 이제 탭을 이동한 후 돌아와도 setTimeout이 정상적으로 작동해있다!