Skip to content

Instantly share code, notes, and snippets.

@lifeart lifeart/ref.js
Last active Sep 17, 2019

Embed
What would you like to do?
JS references
const contextMap = new WeakMap();
function defaultContext() {
return window;
}
function resolveItemAndContext(ctx, item) {
if (item === undefined && typeof ctx === 'string') {
item = ctx;
ctx = defaultContext();
}
return { item, ctx };
}
function emptyReference() {
return {
value() {
return undefined;
},
validate() { return true; },
update() {
return;
}
}
}
function referenceFor(ctx, item) {
if (typeof ctx !== 'object' || ctx === null) {
return emptyReference();
}
if (!contextMap.has(ctx)) {
contextMap.set(ctx, {});
}
const paths = item.split('.');
if (paths.length > 1) {
return referenceFor(referenceFor(ctx, paths.shift()).value(), paths.join('.'));
}
const existingRefs = contextMap.get(ctx);
if (!(item in existingRefs)) {
const ref = {
ver: 0,
value() {
return ctx[item];
},
update(value) {
this.ver++;
ctx[item] = value;
return value;
}
};
existingRefs[item] = ref;
}
return existingRefs[item] ;
}
function get(maybeContxt, maybeItem) {
const { ctx, item } = resolveItemAndContext(maybeContxt, maybeItem);
return referenceFor(ctx, item).value();
}
function set(...args) {
if (args.length <= 1) {
return undefined;
}
if (args.length === 2) {
const { ctx, item } = resolveItemAndContext(args[0]);
return referenceFor(ctx, item).update(args[1]);
} else {
return referenceFor(args[0], args[1]).update(args[2]);
}
}
function r(maybeContxt, maybeItem) {
const { ctx, item } = resolveItemAndContext(maybeContxt, maybeItem);
return referenceFor(ctx, item);
}
r('name').value()
r('name').update(12);
get('name');
set('name', 'foo');
var handler = {
get(target, name){
return get(name);
},
set(target, name, value) {
return set(name, value);
}
};
var globalState = new Proxy({}, handler);
const observersMap = new WeakMap();
const observersSet = new Set();
function observersFor(originalRef) {
return observersMap.get(originalRef);
}
function registerObserver(originalRef, obs) {
if (!observersMap.has(originalRef)) {
observersMap.set(originalRef, []);
}
observersSet.add(obs);
observersMap.get(originalRef).push(obs);
}
function observableRef(trackedRef, cb) {
const ref = {
validate() {
return trackedRef.validate();
},
sync() {
trackedRef.update();
return cb(trackedRef.value());
}
};
registerObserver(trackedRef.ref, ref);
return ref;
}
function trackedRef(ref, maybeCb) {
return {
ver: -1,
computedValue: null,
ref,
validate() {
return this.ver === this.ref.ver;
},
value() {
return this.computedValue;
},
update() {
if (arguments.length === 1) {
this.ref.update(arguments[0]);
}
this.ver = this.ref.ver;
this.computedValue = this.ref.value();
}
}
}
const observalbleRef = observableRef(trackedRef(r('name')), function(newValue){
console.log('newValue');
});
r('name').update('12');
observersFor(r('name')).filter((obs)=>!obs.validate()).forEach((obs)=>obs.sync());
function subscribe(item, cb) {
return observableRef(trackedRef(r(item)), cb);
}
subscribe('name', (value) => { console.log('valueUpdated', value) ;});
function sync() {
observersSet.forEach((value)=>{
if (!value.validate()) { value.sync() };
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.