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.
|
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.
|
`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
|
```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.
|
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.
|
`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
|
```js
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
const ensureArray = require('ensure-array')
|
const ensureArray = require('ensure-array')
|
||||||
const { MultiKeyMap } = require('@vates/multi-key-map')
|
const { MultiKeyMap } = require('@vates/multi-key-map')
|
||||||
|
|
||||||
function State(pGetNewDisposable) {
|
function State(factory) {
|
||||||
this.pGetNewDisposable = pGetNewDisposable
|
this.factory = factory
|
||||||
this.users = 0
|
this.users = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,29 +15,38 @@ exports.deduped = (factory, keyFn = (...args) => args) =>
|
|||||||
const keys = ensureArray(keyFn.apply(this, arguments))
|
const keys = ensureArray(keyFn.apply(this, arguments))
|
||||||
let state = states.get(keys)
|
let state = states.get(keys)
|
||||||
if (state === undefined) {
|
if (state === undefined) {
|
||||||
const pDisposable = factory.apply(this, arguments)
|
const result = factory.apply(this, arguments)
|
||||||
pDisposable.catch(() => {
|
|
||||||
states.delete(keys)
|
|
||||||
})
|
|
||||||
|
|
||||||
state = new State(
|
const createFactory = ({ value, dispose }) => {
|
||||||
pDisposable.then(({ value, dispose }) => {
|
const wrapper = {
|
||||||
const disposeWrapper = () => {
|
dispose() {
|
||||||
if (--state.users === 0) {
|
if (--state.users === 0) {
|
||||||
states.delete(keys)
|
states.delete(keys)
|
||||||
return dispose()
|
return dispose()
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
return () => ({
|
value,
|
||||||
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)
|
states.set(keys, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
++state.users
|
return state.factory()
|
||||||
return state.pGetNewDisposable.then(call)
|
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
@ -40,4 +40,24 @@ describe('deduped()', () => {
|
|||||||
|
|
||||||
expect(dispose).toHaveBeenCalledTimes(1)
|
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