From 43aad3d1174d999518f1ccce5d62ef2c411ebab4 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Wed, 3 Mar 2021 17:42:28 +0100 Subject: [PATCH] feat(disposable/deduped): works with sync factories --- @vates/disposable/README.md | 2 -- @vates/disposable/USAGE.md | 2 -- @vates/disposable/deduped.js | 43 +++++++++++++++++++------------ @vates/disposable/deduped.spec.js | 20 ++++++++++++++ 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/@vates/disposable/README.md b/@vates/disposable/README.md index f0bbcf1f1e..9053358401 100644 --- a/@vates/disposable/README.md +++ b/@vates/disposable/README.md @@ -24,8 +24,6 @@ Creates a new function that wraps `fn` and instead of creating a new disposables Those copies contains the same value and can be disposed independently, the source disposable will only be disposed when all copies are disposed. -`fn` should return a promise containing a disposable. - `keyFn` is called with the same context and arguments as the wrapping function and must returns an array of keys which will be used to identify which disposables should be grouped together. ```js diff --git a/@vates/disposable/USAGE.md b/@vates/disposable/USAGE.md index 013e499987..045a49be56 100644 --- a/@vates/disposable/USAGE.md +++ b/@vates/disposable/USAGE.md @@ -6,8 +6,6 @@ Creates a new function that wraps `fn` and instead of creating a new disposables Those copies contains the same value and can be disposed independently, the source disposable will only be disposed when all copies are disposed. -`fn` should return a promise containing a disposable. - `keyFn` is called with the same context and arguments as the wrapping function and must returns an array of keys which will be used to identify which disposables should be grouped together. ```js diff --git a/@vates/disposable/deduped.js b/@vates/disposable/deduped.js index 737c081eb3..6018728a16 100644 --- a/@vates/disposable/deduped.js +++ b/@vates/disposable/deduped.js @@ -1,8 +1,8 @@ const ensureArray = require('ensure-array') const { MultiKeyMap } = require('@vates/multi-key-map') -function State(pGetNewDisposable) { - this.pGetNewDisposable = pGetNewDisposable +function State(factory) { + this.factory = factory this.users = 0 } @@ -15,29 +15,38 @@ exports.deduped = (factory, keyFn = (...args) => args) => const keys = ensureArray(keyFn.apply(this, arguments)) let state = states.get(keys) if (state === undefined) { - const pDisposable = factory.apply(this, arguments) - pDisposable.catch(() => { - states.delete(keys) - }) + const result = factory.apply(this, arguments) - state = new State( - pDisposable.then(({ value, dispose }) => { - const disposeWrapper = () => { + const createFactory = ({ value, dispose }) => { + const wrapper = { + dispose() { if (--state.users === 0) { states.delete(keys) return dispose() } - } - return () => ({ - dispose: disposeWrapper, - value, - }) + }, + value, + } + + return () => { + ++state.users + return wrapper + } + } + + if (typeof result.then !== 'function') { + state = new State(createFactory(result)) + } else { + result.catch(() => { + states.delete(keys) }) - ) + const pFactory = result.then(createFactory) + state = new State(() => pFactory.then(call)) + } + states.set(keys, state) } - ++state.users - return state.pGetNewDisposable.then(call) + return state.factory() } })() diff --git a/@vates/disposable/deduped.spec.js b/@vates/disposable/deduped.spec.js index 5adf715fff..aace800c5f 100644 --- a/@vates/disposable/deduped.spec.js +++ b/@vates/disposable/deduped.spec.js @@ -40,4 +40,24 @@ describe('deduped()', () => { expect(dispose).toHaveBeenCalledTimes(1) }) + + it('works with sync factory', () => { + const value = {} + const dispose = jest.fn() + const dedupedGetResource = deduped(() => ({ value, dispose })) + + const d1 = dedupedGetResource() + expect(d1.value).toBe(value) + + const d2 = dedupedGetResource() + expect(d2.value).toBe(value) + + d1.dispose() + + expect(dispose).not.toHaveBeenCalled() + + d2.dispose() + + expect(dispose).toHaveBeenCalledTimes(1) + }) })