UNPKG

kr-observable

Version:
83 lines (82 loc) 2.31 kB
import { Global } from './global.js'; const queue = Global.queue; const notifier = Global.notifier; export class Admin { static meta = { key: '', adm: new Admin('') }; owner; deps = new Map; listeners; changes = new Set; current = null; queued = false; constructor(owner) { this.owner = owner; } subscribe(property, runnable) { let list = this.deps.get(property); if (!list) { list = new Set; this.deps.set(property, list); } if (!list.has(runnable)) { list.add(runnable); if (!runnable.deps?.has(list)) { runnable.deps?.add(list); } } } unsubscribe(property, runnable) { this.deps.get(property)?.delete(runnable); } report(property, value) { this.listeners?.forEach(cb => cb(property, value)); if (!this.deps.has(property)) return; this.changes.add(property); if (Global.action) { queue.add(this); } else { if (this.queued) return; this.queued = true; queueMicrotask(this.enqueueBatch); } } enqueueBatch = () => { this.batch(); this.queued = false; }; batch(flag = false) { if (this.changes.size === 0) return; const changes = this.changes; if (changes.size > 1) { const copy = new Set(); for (const key of this.deps.keys()) { if (changes.has(key)) copy.add(key); } this.changes = copy; } for (const change of this.changes) { this.changes.delete(change); this.current = this.deps.get(change); for (const sub of this.current) { if (sub.runId !== notifier.runId) { if (sub.active) { return; } if (flag && sub.computed) { return this.changes.add(change); } notifier.notify(sub, changes); } } this.current = null; } } static batch(adm) { adm.batch(); } }