Skip to content

Commit

Permalink
enh(lazyTimer): options minInterval and maxDelay
Browse files Browse the repository at this point in the history
Signed-off-by: Max <max@nextcloud.com>
  • Loading branch information
max-nextcloud committed Feb 16, 2023
1 parent 137bc9d commit 5e41593
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 13 deletions.
25 changes: 18 additions & 7 deletions src/helpers/lazy.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,23 @@
*/

/**
* Call callback in intervals that double
*
* Returns a handle to modify the interval:
* - handle.wakeUp() resets it to the minimum.
* - handle.sleep() uses maximum interval right away.
* - handle.interval can be used to clear the interval:
* `clearInterval(handle.interval)`
*
* @param {Function} callback to be triggered by the timer
* @param {object} options optional
* @param {number} options.minInterval minimum interval between two calls
* @param {number} options.maxDelay maximum factor to multiply the interval by
* @return {Function} handle to modify behavior
*/
function lazyTimer(callback) {
const fn = lazy(callback)
fn.interval = setInterval(fn, 300)
function lazyTimer(callback, { minInterval = 300, maxDelay = 16 } = {}) {
const fn = lazy(callback, { maxDelay })
fn.interval = setInterval(fn, minInterval)
return fn
}

Expand All @@ -48,16 +59,16 @@ export { lazyTimer }
*
* @param {Function} inner function to be called
* @param {object} options optional
* @param {number} options.maxInterval maximum interval between two calls to inner
* @param {number} options.maxDelay maximum interval between two calls to inner
*/
export function lazy(inner, { maxInterval = 16 } = {}) {
export function lazy(inner, { maxDelay = 16 } = {}) {
let count = 0
let interval = 1
const result = (...args) => {
count++
if (count === interval) {
count = 0
interval = Math.min(interval * 2, maxInterval)
interval = Math.min(interval * 2, maxDelay)
return inner(...args)
}
}
Expand All @@ -66,7 +77,7 @@ export function lazy(inner, { maxInterval = 16 } = {}) {
interval = 1
}
result.sleep = () => {
interval = maxInterval
interval = maxDelay
}
return result
}
24 changes: 18 additions & 6 deletions src/tests/helpers/lazy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,19 @@ describe('lazy timer', () => {
jest.useRealTimers()
})

test('stays at same interval once it reached maxInterval', () => {
test('allows configuring min and max intervals', () => {
jest.useFakeTimers()
const callback = jest.fn();
const timer = lazyTimer(callback, { minInterval: 10, maxDelay: 2 });
expect(callback).not.toBeCalled();
jest.advanceTimersByTime(40);
expect(callback).toHaveBeenCalledTimes(2); // 10, 30
jest.advanceTimersByTime(40);
expect(callback).toHaveBeenCalledTimes(4); // 50, 70
jest.useRealTimers()
})

test('stays at same interval once it reached maxDelay', () => {
jest.useFakeTimers()
const callback = jest.fn();
const timer = lazyTimer(callback);
Expand Down Expand Up @@ -50,7 +62,7 @@ describe('lazy timer', () => {
jest.useRealTimers()
})

test('goes to maxInterval when sleep is called', () => {
test('goes to maxDelay when sleep is called', () => {
jest.useFakeTimers()
const callback = jest.fn();
const timer = lazyTimer(callback);
Expand Down Expand Up @@ -114,22 +126,22 @@ describe('lazy function', () => {

test('respects skipAtMost option', () => {
const inner = jest.fn()
const fn = lazy(inner, { maxInterval: 4 })
const fn = lazy(inner, { maxDelay: 4 })
callNTimes(20, fn)
expect(inner.mock.calls.map(call => call[0])).toEqual([1,3,7,11,15,19])
})

test('maxInterval defaults to 16', () => {
test('maxDelay defaults to 16', () => {
const inner = jest.fn()
const fn = lazy(inner)
callNTimes(64, fn)
expect(inner.mock.calls.map(call => call[0])).toEqual([1,3,7,15,31,47,63])
})

test('Uses maxInterval after sleep was called', () => {
test('Uses maxDelay after sleep was called', () => {
const inner = jest.fn()
let count = 0
const lazyFn = lazy(() => inner(count), { maxInterval: 6 })
const lazyFn = lazy(() => inner(count), { maxDelay: 6 })
const trigger = () => {
count++
lazyFn()
Expand Down

0 comments on commit 5e41593

Please sign in to comment.