feat(disposable/deduped): works with sync factories
This commit is contained in:
parent
f2d4fdd4d2
commit
43aad3d117
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
})()
|
||||
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user