53 lines
1.3 KiB
JavaScript
53 lines
1.3 KiB
JavaScript
const ensureArray = require('ensure-array')
|
|
const { MultiKeyMap } = require('@vates/multi-key-map')
|
|
|
|
function State(factory) {
|
|
this.factory = factory
|
|
this.users = 0
|
|
}
|
|
|
|
const call = fn => fn()
|
|
|
|
exports.deduped = (factory, keyFn = (...args) => args) =>
|
|
(function () {
|
|
const states = new MultiKeyMap()
|
|
return function () {
|
|
const keys = ensureArray(keyFn.apply(this, arguments))
|
|
let state = states.get(keys)
|
|
if (state === undefined) {
|
|
const result = factory.apply(this, arguments)
|
|
|
|
const createFactory = disposable => {
|
|
const wrapper = {
|
|
dispose() {
|
|
if (--state.users === 0) {
|
|
states.delete(keys)
|
|
return disposable.dispose()
|
|
}
|
|
},
|
|
value: disposable.value,
|
|
}
|
|
|
|
return () => {
|
|
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.factory()
|
|
}
|
|
})()
|