Skip to main content
Module

x/solid/bench/sinuous-mod.cjs

A declarative, efficient, and flexible JavaScript library for building user interfaces.
Go to Latest
File
function getChildrenDeep(children, res) { for (let i = 0; i < children.length; i += 1) { res.push(children[i]); getChildrenDeep(children[0]._children, res); }}
const EMPTY_ARR = [];let tracking;let queue;
/** * Returns true if there is an active observer. * @return {boolean} */function isListening() { return !!tracking;}
/** * Creates a root and executes the passed function that can contain computations. * The executed function receives an `unsubscribe` argument which can be called to * unsubscribe all inner computations. * * @param {Function} fn * @return {*} */function createRoot(fn) { const prevTracking = tracking, rootUpdate = { _children: [] }; tracking = rootUpdate; const result = fn(() => { _unsubscribe(rootUpdate); tracking = undefined; }); tracking = prevTracking; return result;}
function sample(fn) { const prevTracking = tracking; tracking = undefined; const value = fn(); tracking = prevTracking; return value;}
function batch(fn) { let prevQueue = queue; queue = []; const result = fn(); let q = queue; queue = prevQueue; for (let i = 0; i < q.length; i += 1) { const data = q[i]; if (data._pending !== EMPTY_ARR) { const pending = data._pending; data._pending = EMPTY_ARR; data(pending); } } return result;}
class DataNode { constructor(value) { this._observers = new Set(); this._pending = EMPTY_ARR; this.value = value; this._runObservers = null; } current() { if (tracking && tracking._observables && !this._observers.has(tracking)) { this._observers.add(tracking); tracking._observables.push(this); } return this.value; } next(nextValue) { if (queue) { if (this._pending === EMPTY_ARR) { queue.push(this); } this._pending = nextValue; return nextValue; }
this.value = nextValue;
// Clear `tracking` otherwise a computed triggered by a set // in another computed is seen as a child of that other computed. const clearedUpdate = tracking; tracking = undefined;
// Update can alter data._observers, make a copy before running. this._runObservers = new Set(this._observers); for (const v of this._runObservers.values()) v._fresh = false; for (const v of this._runObservers.values()) !v._fresh && updateComputation(v);
tracking = clearedUpdate; return this.value; }}
function createComputationNode(observer, value) { const c = { observer, value, _fresh: false, _observables: [], _children: [], _cleanups: [] }; updateComputation(c); return c;}
function removeFreshChildren(u) { if (u._fresh) { for (let i = 0, len = u._observables.length; i < len; i += 1) { const o = u._observables[i]; o._runObservers && o._runObservers.delete(u); } }}
function onCleanup(fn) { if (tracking) { tracking._cleanups.push(fn); } return fn;}
function _unsubscribe(node) { let i; for (i = 0; i < node._children.length; i += 1) _unsubscribe(node._children[i]); for (i = 0; i < node._observables.length; i += 1) { const o = node._observables[i]; o._observers.delete(node); o._runObservers && o._runObservers.delete(node); } for (i = 0; i < node._cleanups.length; i += 1) node._cleanups[i](); resetUpdate(node);}
function updateComputation(node) { if (!node.observer) return; const prevTracking = tracking; if (tracking) { tracking._children.push(node); }
const prevChildren = node._children;
_unsubscribe(node); node._fresh = true; tracking = node; node.value = node.observer(node.value);
// If any children computations were removed mark them as fresh. // Check the diff of the children list between pre and post update. const pK = Object.keys(prevChildren); for (let i = 0, len = pK.length; i < len; i += 1) { const u = prevChildren[i]; if (node._children.indexOf(u) === -1) { u._fresh = true; } }
// If any children were marked as fresh remove them from the run lists. const allChildren = []; getChildrenDeep(node._children, allChildren); for (let i = 0; i < allChildren.length; i += 1) removeFreshChildren(allChildren[i]);
tracking = prevTracking; return node.value;}
function currentValue() { if (this._fresh) { for (let i = 0; i < this._observables.length; i += 1) this._observables[i].current(); } else { this.value = updateComputation(this); } return this.value;}
function resetUpdate(node) { // Keep track of which observables trigger nodes. Needed for unsubscribe. node._observables = []; node._children = []; node._cleanups = [];}
module.exports = { createSignal: value => { const o = new DataNode(value); return [o.current.bind(o), o.next.bind(o)]; }, createRoot, createComputed: (observer, seed) => createComputationNode(observer, seed), createMemo: (observer, seed) => { const c = createComputationNode(observer, seed); return currentValue.bind(c); }};