You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
83 lines
3.2 KiB
83 lines
3.2 KiB
import { dep, Slot } from "optimism"; |
|
// Contextual Slot that acquires its value when custom read functions are |
|
// called in Policies#readField. |
|
export var cacheSlot = new Slot(); |
|
var cacheInfoMap = new WeakMap(); |
|
function getCacheInfo(cache) { |
|
var info = cacheInfoMap.get(cache); |
|
if (!info) { |
|
cacheInfoMap.set(cache, (info = { |
|
vars: new Set(), |
|
dep: dep(), |
|
})); |
|
} |
|
return info; |
|
} |
|
export function forgetCache(cache) { |
|
getCacheInfo(cache).vars.forEach(function (rv) { return rv.forgetCache(cache); }); |
|
} |
|
// Calling forgetCache(cache) serves to silence broadcasts and allows the |
|
// cache to be garbage collected. However, the varsByCache WeakMap |
|
// preserves the set of reactive variables that were previously associated |
|
// with this cache, which makes it possible to "recall" the cache at a |
|
// later time, by reattaching it to those variables. If the cache has been |
|
// garbage collected in the meantime, because it is no longer reachable, |
|
// you won't be able to call recallCache(cache), and the cache will |
|
// automatically disappear from the varsByCache WeakMap. |
|
export function recallCache(cache) { |
|
getCacheInfo(cache).vars.forEach(function (rv) { return rv.attachCache(cache); }); |
|
} |
|
export function makeVar(value) { |
|
var caches = new Set(); |
|
var listeners = new Set(); |
|
var rv = function (newValue) { |
|
if (arguments.length > 0) { |
|
if (value !== newValue) { |
|
value = newValue; |
|
caches.forEach(function (cache) { |
|
// Invalidate any fields with custom read functions that |
|
// consumed this variable, so query results involving those |
|
// fields will be recomputed the next time we read them. |
|
getCacheInfo(cache).dep.dirty(rv); |
|
// Broadcast changes to any caches that have previously read |
|
// from this variable. |
|
broadcast(cache); |
|
}); |
|
// Finally, notify any listeners added via rv.onNextChange. |
|
var oldListeners = Array.from(listeners); |
|
listeners.clear(); |
|
oldListeners.forEach(function (listener) { return listener(value); }); |
|
} |
|
} |
|
else { |
|
// When reading from the variable, obtain the current cache from |
|
// context via cacheSlot. This isn't entirely foolproof, but it's |
|
// the same system that powers varDep. |
|
var cache = cacheSlot.getValue(); |
|
if (cache) { |
|
attach(cache); |
|
getCacheInfo(cache).dep(rv); |
|
} |
|
} |
|
return value; |
|
}; |
|
rv.onNextChange = function (listener) { |
|
listeners.add(listener); |
|
return function () { |
|
listeners.delete(listener); |
|
}; |
|
}; |
|
var attach = (rv.attachCache = function (cache) { |
|
caches.add(cache); |
|
getCacheInfo(cache).vars.add(rv); |
|
return rv; |
|
}); |
|
rv.forgetCache = function (cache) { return caches.delete(cache); }; |
|
return rv; |
|
} |
|
function broadcast(cache) { |
|
if (cache.broadcastWatches) { |
|
cache.broadcastWatches(); |
|
} |
|
} |
|
//# sourceMappingURL=reactiveVars.js.map
|