Skip to content

Commit

Permalink
feat: optimize timer behavior in background tabs
Browse files Browse the repository at this point in the history
- Implement different timer strategies for foreground/background states
- Use setInterval for smooth updates in foreground (1000ms)
- Switch to setTimeout for one-time update in background
- Add visibility change detection to handle tab state changes
- Immediately update timer display when switching between states
- Clean up timers properly when stopping or switching states

This change improves timer accuracy and reduces resource usage when the tab is in background.
  • Loading branch information
bobchao committed Nov 5, 2024
1 parent 2885d23 commit 1e3fc0f
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 36 deletions.
16 changes: 12 additions & 4 deletions script.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,15 @@ document.addEventListener('DOMContentLoaded', () => {
this.handleEnd();
}
};

// 監聽頁面可見性變化
document.addEventListener('visibilitychange', () => {
const isBackground = document.hidden;
this.worker.postMessage({
command: 'visibility-change',
isBackground: isBackground
});
});
},

handleTick(workerRemainingTime) {
Expand Down Expand Up @@ -434,12 +443,11 @@ document.addEventListener('DOMContentLoaded', () => {
},

start() {
// 確保先停止現有計時器
this.stop();
// 發送開始命令 worker
const isBackground = document.hidden;
this.worker.postMessage({
command: 'start',
time: state.remainingTime
time: state.remainingTime,
isBackground: isBackground
});
},

Expand Down
128 changes: 96 additions & 32 deletions timeWorker.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,104 @@
let targetEndTime = null;
let timerInterval = null;
let updateInterval = null;
let backgroundTimeout = null;
let isInBackground = false;

self.onmessage = function(event) {
const { command, time } = event.data;
// 處理前景更新
function handleForegroundUpdate() {
if (updateInterval) {
clearInterval(updateInterval);
}

if (command === 'start') {
// 清除現有計時器
if (timerInterval) {
clearInterval(timerInterval);
}

// 只記錄目標結束時間
targetEndTime = Date.now() + time;

// 使用 1 秒的更新頻率
timerInterval = setInterval(() => {
const now = Date.now();
const remainingTime = Math.max(0, targetEndTime - now);
updateInterval = setInterval(() => {
sendTimeUpdate();
}, 1000);
}

if (remainingTime > 0) {
self.postMessage({
command: 'tick',
remainingTime: remainingTime
});
// 處理背景更新
function handleBackgroundUpdate() {
// 清除前景的 interval
if (updateInterval) {
clearInterval(updateInterval);
updateInterval = null;
}

const now = Date.now();
const remainingTime = targetEndTime - now;

if (remainingTime > 0) {
// 設置一次性 timeout 到結束時間
backgroundTimeout = setTimeout(() => {
sendTimeUpdate();
self.postMessage({ command: 'end' });
}, remainingTime);
}
}

// 發送時間更新
function sendTimeUpdate() {
if (!targetEndTime) return;

const now = Date.now();
const remainingTime = Math.max(0, targetEndTime - now);

if (remainingTime > 0) {
self.postMessage({
command: 'tick',
remainingTime: remainingTime
});
} else {
// 清理所有計時器
cleanup();
self.postMessage({ command: 'end' });
}
}

// 清理函數
function cleanup() {
if (updateInterval) {
clearInterval(updateInterval);
updateInterval = null;
}
if (backgroundTimeout) {
clearTimeout(backgroundTimeout);
backgroundTimeout = null;
}
}

self.onmessage = function(event) {
const { command, time, isBackground } = event.data;

switch (command) {
case 'start':
cleanup();
targetEndTime = Date.now() + time;
isInBackground = isBackground;

if (isBackground) {
handleBackgroundUpdate();
} else {
clearInterval(timerInterval);
timerInterval = null;
self.postMessage({ command: 'end' });
handleForegroundUpdate();
}
// 立即發送第一次更新
sendTimeUpdate();
break;

case 'stop':
cleanup();
targetEndTime = null;
break;

case 'visibility-change':
isInBackground = isBackground;
if (targetEndTime) {
if (isBackground) {
handleBackgroundUpdate();
} else {
handleForegroundUpdate();
}
// 切換時立即更新一次
sendTimeUpdate();
}
}, 1000);

} else if (command === 'stop') {
if (timerInterval) {
clearInterval(timerInterval);
timerInterval = null;
}
targetEndTime = null;
break;
}
};

0 comments on commit 1e3fc0f

Please sign in to comment.