diff --git a/src/background-store.js b/src/background-store.js index 15866be..57df033 100644 --- a/src/background-store.js +++ b/src/background-store.js @@ -6,7 +6,9 @@ import { UPDATE_STATE } from './constants'; -let store, actions, onDisconnect; +import utils from './utils'; + +let store, actions, onDisconnect, debounceDelay; // eslint-disable-next-line consistent-return function handleMessage( @@ -40,13 +42,19 @@ function handleConnection(connection: Connection): void { return; } - // send updated state to other parts of the app on every change - const unsubscribe = store.subscribe(() => { + let onStoreEvent = () => { connection.postMessage({ type: UPDATE_STATE, data: store.getState() }); - }); + }; + + if (debounceDelay) { + onStoreEvent = utils.debounce(onStoreEvent, debounceDelay); + } + + // send updated state to other parts of the app on every change + const unsubscribe = store.subscribe(onStoreEvent); // unsubscribe on disconnect connection.onDisconnect.addListener(() => { @@ -61,7 +69,8 @@ function handleConnection(connection: Connection): void { export default function createBackgroundStore(options: { store: Store, actions?: Object, - onDisconnect?: EmptyFunc + onDisconnect?: EmptyFunc, + debounceDelay?: number }): Store { if (typeof options !== 'object' || typeof options.store !== 'object') { throw new Error('Expected the "store" to be an object.'); @@ -75,9 +84,14 @@ export default function createBackgroundStore(options: { throw new Error('Expected the "onDisconnect" to be a function.'); } + if (options.hasOwnProperty('debounceDelay') && typeof options.debounceDelay !== 'number') { + throw new Error('Expected the "debounceDelay" to be a number'); + } + store = options.store; actions = options.actions || {}; onDisconnect = options.onDisconnect; + debounceDelay = options.debounceDelay; chrome.runtime.onConnect.addListener(handleConnection); chrome.runtime.onMessage.addListener(handleMessage); diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..417e18f --- /dev/null +++ b/src/utils.js @@ -0,0 +1,12 @@ +/* @flow */ + +const debounce = (func: (...args: any) => void, delay: number) => { + let inDebounce; + return function (...args: any) { + const context: any = this; + clearTimeout(inDebounce); + inDebounce = setTimeout(() => func.apply(context, args), delay); + }; +}; + +export default {debounce}; diff --git a/tests/background-store.js b/tests/background-store.js index feeda02..0ead239 100644 --- a/tests/background-store.js +++ b/tests/background-store.js @@ -4,6 +4,7 @@ import { UPDATE_STATE } from '../src/constants'; import createBackgroundStore from '../src/background-store'; +import utils from '../src/utils'; function createStore(params) { window.chrome = { @@ -53,6 +54,12 @@ describe('background-store', () => { onDisconnect: true })).toThrowError(/onDisconnect/); }); + it('debounceDelay is not a number', () => { + expect(() => createBackgroundStore({ + store: {}, + debounceDelay: true + })).toThrowError(/debounceDelay/); + }); }); it('returns the same store', () => { @@ -65,8 +72,9 @@ describe('background-store', () => { }); describe('handle connection', () => { - function testCase(onDisconnect) { + function testCase(onDisconnect, debounceDelay) { const unsubscribe = jest.fn(); + const options = { store: { subscribe: jest.fn(() => unsubscribe), @@ -78,6 +86,10 @@ describe('background-store', () => { options.onDisconnect = onDisconnect; } + if (debounceDelay) { + options.debounceDelay = debounceDelay; + } + const {store, handleConnect} = createStore(options); const connection = { name: CONNECTION_NAME, @@ -91,9 +103,7 @@ describe('background-store', () => { expect(store.subscribe).lastCalledWith(jasmine.any(Function)); expect(connection.onDisconnect.addListener).lastCalledWith(jasmine.any(Function)); - store.subscribe.mock.calls[0][0](); - expect(store.getState).lastCalledWith(); expect(connection.postMessage).lastCalledWith({ type: UPDATE_STATE, @@ -151,6 +161,12 @@ describe('background-store', () => { expect(unsubscribe).lastCalledWith(); expect(onDisconnect).lastCalledWith(); }); + + it('with provided debounceDelay callback', () => { + utils.debounce = jest.fn(((func) => func)); + testCase(null, 1000); + expect(utils.debounce).lastCalledWith(jasmine.any(Function), 1000); + }); }); });