diff --git a/src/routes/_store/observers/cleanup.js b/src/routes/_store/observers/cleanup.js index d2e8279a..f149b6fe 100644 --- a/src/routes/_store/observers/cleanup.js +++ b/src/routes/_store/observers/cleanup.js @@ -1,6 +1,7 @@ import { store } from '../store' import { scheduleIdleTask } from '../../_utils/scheduleIdleTask' import { CLEANUP_DELAY, CLEANUP_TIME_AGO } from '../../_static/database' +import { scheduleInterval } from '../../_utils/scheduleInterval' function doCleanup () { // Periodically clean up drafts in localStorage, so they don't grow without bound. @@ -26,6 +27,10 @@ function doCleanup () { } } -export function cleanup () { - setInterval(() => scheduleIdleTask(doCleanup), CLEANUP_DELAY) +function doCleanupLazily () { + scheduleIdleTask(doCleanup) +} + +export function cleanup () { + scheduleInterval(doCleanupLazily, CLEANUP_DELAY, /* runOnActive */ false) } diff --git a/src/routes/_store/observers/nowObservers.js b/src/routes/_store/observers/nowObservers.js index df055e62..37327e10 100644 --- a/src/routes/_store/observers/nowObservers.js +++ b/src/routes/_store/observers/nowObservers.js @@ -1,47 +1,20 @@ // For convenience, periodically re-compute the current time. This ensures freshness of // displays like "x minutes ago" without having to jump through a lot of hoops. import { scheduleIdleTask } from '../../_utils/scheduleIdleTask' -import lifecycle from 'page-lifecycle/dist/lifecycle.mjs' +import { scheduleInterval } from '../../_utils/scheduleInterval' const POLL_INTERVAL = 10000 export function nowObservers (store) { - let interval - function updateNow () { store.set({ now: Date.now() }) } - function startPolling () { - interval = setInterval(() => scheduleIdleTask(updateNow), POLL_INTERVAL) - } - - function stopPolling () { - if (interval) { - clearInterval(interval) - interval = null - } - } - - function restartPolling () { - stopPolling() + function updateNowLazily () { scheduleIdleTask(updateNow) - startPolling() } updateNow() - if (process.browser) { - startPolling() - - lifecycle.addEventListener('statechange', e => { - if (e.newState === 'passive') { - console.log('stopping Date.now() observer...') - stopPolling() - } else if (e.newState === 'active') { - console.log('restarting Date.now() observer...') - restartPolling() - } - }) - } + scheduleInterval(updateNowLazily, POLL_INTERVAL, /* runOnActive */ true) } diff --git a/src/routes/_utils/scheduleInterval.js b/src/routes/_utils/scheduleInterval.js new file mode 100644 index 00000000..6df23eae --- /dev/null +++ b/src/routes/_utils/scheduleInterval.js @@ -0,0 +1,48 @@ +import lifecycle from 'page-lifecycle/dist/lifecycle.mjs' + +/** + * Schedule a callback, similar to setInterval but disables itself when the page is not active to save battery/CPU. + * @param callback - callback to run + * @param delay - how many milliseconds between callback calls + * @param runOnActive - whether to run immediately when the page switches to an "active" state + */ +export function scheduleInterval (callback, delay, runOnActive) { + let interval + + function startPolling () { + interval = setInterval(callback, delay) + } + + function stopPolling () { + if (interval) { + clearInterval(interval) + interval = null + } + } + + function restartPolling () { + stopPolling() + if (runOnActive) { + try { + callback() + } catch (e) { + console.warn(e) + } + } + startPolling() + } + + if (process.browser) { + startPolling() + + lifecycle.addEventListener('statechange', e => { + if (e.newState === 'passive') { + console.log('pausing interval...') + stopPolling() + } else if (e.newState === 'active') { + console.log('restarting interval...') + restartPolling() + } + }) + } +}