Skip to content

Instantly share code, notes, and snippets.

@benjamingr
Created June 18, 2018 14:33
Show Gist options
  • Save benjamingr/8098901205a0eb5bfd6a664c584ebc6c to your computer and use it in GitHub Desktop.
Save benjamingr/8098901205a0eb5bfd6a664c584ebc6c to your computer and use it in GitHub Desktop.
class Reactor {
constructor() {
// this keeps the current function we're reacting to
this.reaction = null;
}
// observe a single property
_observeProperty(obj, prop, initialValue = undefined) {
let backing = initialValue;
let dependents = [];
Object.defineProperty(obj, prop, {
get: () => {
if (this.reaction) {
dependents.push(this.reaction);
}
return backing;
},
set(value) {
backing = value;
for(const dependent of dependents) {
setTimeout(dependent); /// <- ONLY LINE THAT I HAD TO CHANGE IS THIS ONE
}
}
});
}
// observe a whole object
_observeObject(obj) {
for(const p of Object.keys(obj)) {
this.observe(obj, p, obj[p]);
}
return obj;
}
// convenience
observe(obj, prop, initialValue = undefined) {
if (typeof prop === 'undefined') return this._observeObject(obj);
return this._observeProperty(obj, prop, initialValue);
}
// computed is just observe + autorun, we should fix the setter
computed(obj, prop, fn) {
this._observeProperty(obj, prop, fn());
this.autorun(() => {
obj[prop] = fn();
});
}
// see how simple this is - we just see what getters are called (by setting this.reaction) and telling them to
// re-run this later
autorun(fn) {
this.reaction = fn; // can't nest autoruns because that's lame
try {
return fn(); // get initial depenedents
} finally {
this.reaction = null;
}
}
}
let r = new Reactor();
var o = r.observe({
a: 3,
b: 5,
r: 'foo'
});
r.computed(o, 'full', () => o.a + o.b);
//r.observe(o, 'r', 3);
r.autorun(() => console.log(o.full));
o.a = 1;
o.a = 2;
o.a = 3;
o.b = 4;
/*
~/Desktop $ node magic.js
8
6
7
8
7
*/
class Reactor {
constructor() {
// this keeps the current function we're reacting to
this.reaction = null;
}
// observe a single property
_observeProperty(obj, prop, initialValue = undefined) {
let backing = initialValue;
let dependents = [];
Object.defineProperty(obj, prop, {
get: () => {
if (this.reaction) {
dependents.push(this.reaction);
}
return backing;
},
set(value) {
backing = value;
for(const dependent of dependents) {
dependent();
}
}
});
}
// observe a whole object
_observeObject(obj) {
for(const p of Object.keys(obj)) {
this.observe(obj, p, obj[p]);
}
return obj;
}
// convenience
observe(obj, prop, initialValue = undefined) {
if (typeof prop === 'undefined') return this._observeObject(obj);
return this._observeProperty(obj, prop, initialValue);
}
// computed is just observe + autorun, we should fix the setter
computed(obj, prop, fn) {
this._observeProperty(obj, prop, fn());
this.autorun(() => {
obj[prop] = fn();
});
}
// see how simple this is - we just see what getters are called (by setting this.reaction) and telling them to
// re-run this later
autorun(fn) {
this.reaction = fn; // can't nest autoruns because that's lame
try {
return fn(); // get initial depenedents
} finally {
this.reaction = null;
}
}
}
let r = new Reactor();
var o = r.observe({
a: 3,
b: 5,
r: 'foo'
});
r.computed(o, 'full', () => o.a + o.b);
//r.observe(o, 'r', 3);
r.autorun(() => console.log(o.full));
o.a = 1;
o.a = 2;
o.a = 3;
o.b = 4;
/*
~/Desktop $ node magic.js
8
6
7
8
7
*/
@benjamingr
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment