UNPKG

@tanstack/store

Version:

Framework agnostic type-safe store w/ reactive framework adapters

1 lines 6.58 kB
{"version":3,"file":"scheduler.cjs","sources":["../../src/scheduler.ts"],"sourcesContent":["import { Derived } from './derived'\nimport type { Store } from './store'\n\n/**\n * This is here to solve the pyramid dependency problem where:\n * A\n * / \\\n * B C\n * \\ /\n * D\n *\n * Where we deeply traverse this tree, how do we avoid D being recomputed twice; once when B is updated, once when C is.\n *\n * To solve this, we create linkedDeps that allows us to sync avoid writes to the state until all of the deps have been\n * resolved.\n *\n * This is a record of stores, because derived stores are not able to write values to, but stores are\n */\nexport const __storeToDerived = new WeakMap<\n Store<unknown>,\n Set<Derived<unknown>>\n>()\nexport const __derivedToStore = new WeakMap<\n Derived<unknown>,\n Set<Store<unknown>>\n>()\n\nexport const __depsThatHaveWrittenThisTick = {\n current: [] as Array<Derived<unknown> | Store<unknown>>,\n}\n\nlet __isFlushing = false\nlet __batchDepth = 0\nconst __pendingUpdates = new Set<Store<unknown>>()\n// Add a map to store initial values before batch\nconst __initialBatchValues = new Map<Store<unknown>, unknown>()\n\nfunction __flush_internals(relatedVals: Set<Derived<unknown>>) {\n // First sort deriveds by dependency order\n const sorted = Array.from(relatedVals).sort((a, b) => {\n // If a depends on b, b should go first\n if (a instanceof Derived && a.options.deps.includes(b)) return 1\n // If b depends on a, a should go first\n if (b instanceof Derived && b.options.deps.includes(a)) return -1\n return 0\n })\n\n for (const derived of sorted) {\n if (__depsThatHaveWrittenThisTick.current.includes(derived)) {\n continue\n }\n\n __depsThatHaveWrittenThisTick.current.push(derived)\n derived.recompute()\n\n const stores = __derivedToStore.get(derived)\n if (stores) {\n for (const store of stores) {\n const relatedLinkedDerivedVals = __storeToDerived.get(store)\n if (!relatedLinkedDerivedVals) continue\n __flush_internals(relatedLinkedDerivedVals)\n }\n }\n }\n}\n\nfunction __notifyListeners(store: Store<unknown>) {\n store.listeners.forEach((listener) =>\n listener({\n prevVal: store.prevState as never,\n currentVal: store.state as never,\n }),\n )\n}\n\nfunction __notifyDerivedListeners(derived: Derived<unknown>) {\n derived.listeners.forEach((listener) =>\n listener({\n prevVal: derived.prevState as never,\n currentVal: derived.state as never,\n }),\n )\n}\n\n/**\n * @private only to be called from `Store` on write\n */\nexport function __flush(store: Store<unknown>) {\n // If we're starting a batch, store the initial values\n if (__batchDepth > 0 && !__initialBatchValues.has(store)) {\n __initialBatchValues.set(store, store.prevState)\n }\n\n __pendingUpdates.add(store)\n\n if (__batchDepth > 0) return\n if (__isFlushing) return\n\n try {\n __isFlushing = true\n\n while (__pendingUpdates.size > 0) {\n const stores = Array.from(__pendingUpdates)\n __pendingUpdates.clear()\n\n // First notify listeners with updated values\n for (const store of stores) {\n // Use initial batch values for prevState if we have them\n const prevState = __initialBatchValues.get(store) ?? store.prevState\n store.prevState = prevState\n __notifyListeners(store)\n }\n\n // Then update all derived values\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n __depsThatHaveWrittenThisTick.current.push(store)\n __flush_internals(derivedVals)\n }\n\n // Notify derived listeners after recomputing\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n for (const derived of derivedVals) {\n __notifyDerivedListeners(derived)\n }\n }\n }\n } finally {\n __isFlushing = false\n __depsThatHaveWrittenThisTick.current = []\n __initialBatchValues.clear()\n }\n}\n\nexport function batch(fn: () => void) {\n __batchDepth++\n try {\n fn()\n } finally {\n __batchDepth--\n if (__batchDepth === 0) {\n const pendingUpdateToFlush = Array.from(__pendingUpdates)[0] as\n | Store<unknown>\n | undefined\n if (pendingUpdateToFlush) {\n __flush(pendingUpdateToFlush) // Trigger flush of all pending updates\n }\n }\n }\n}\n"],"names":["Derived","derived","store"],"mappings":";;;AAkBa,MAAA,uCAAuB,QAGlC;AACW,MAAA,uCAAuB,QAGlC;AAEK,MAAM,gCAAgC;AAAA,EAC3C,SAAS,CAAA;AACX;AAEA,IAAI,eAAe;AACnB,IAAI,eAAe;AACnB,MAAM,uCAAuB,IAAoB;AAEjD,MAAM,2CAA2B,IAA6B;AAE9D,SAAS,kBAAkB,aAAoC;AAEvD,QAAA,SAAS,MAAM,KAAK,WAAW,EAAE,KAAK,CAAC,GAAG,MAAM;AAEhD,QAAA,aAAaA,mBAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAU,QAAA;AAE3D,QAAA,aAAaA,mBAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAU,QAAA;AACxD,WAAA;AAAA,EAAA,CACR;AAED,aAAWC,YAAW,QAAQ;AAC5B,QAAI,8BAA8B,QAAQ,SAASA,QAAO,GAAG;AAC3D;AAAA,IAAA;AAG4B,kCAAA,QAAQ,KAAKA,QAAO;AAClD,IAAAA,SAAQ,UAAU;AAEZ,UAAA,SAAS,iBAAiB,IAAIA,QAAO;AAC3C,QAAI,QAAQ;AACV,iBAAW,SAAS,QAAQ;AACpB,cAAA,2BAA2B,iBAAiB,IAAI,KAAK;AAC3D,YAAI,CAAC,yBAA0B;AAC/B,0BAAkB,wBAAwB;AAAA,MAAA;AAAA,IAC5C;AAAA,EACF;AAEJ;AAEA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,UAAU;AAAA,IAAQ,CAAC,aACvB,SAAS;AAAA,MACP,SAAS,MAAM;AAAA,MACf,YAAY,MAAM;AAAA,IACnB,CAAA;AAAA,EACH;AACF;AAEA,SAAS,yBAAyBA,UAA2B;AAC3D,EAAAA,SAAQ,UAAU;AAAA,IAAQ,CAAC,aACzB,SAAS;AAAA,MACP,SAASA,SAAQ;AAAA,MACjB,YAAYA,SAAQ;AAAA,IACrB,CAAA;AAAA,EACH;AACF;AAKO,SAAS,QAAQ,OAAuB;AAE7C,MAAI,eAAe,KAAK,CAAC,qBAAqB,IAAI,KAAK,GAAG;AACnC,yBAAA,IAAI,OAAO,MAAM,SAAS;AAAA,EAAA;AAGjD,mBAAiB,IAAI,KAAK;AAE1B,MAAI,eAAe,EAAG;AACtB,MAAI,aAAc;AAEd,MAAA;AACa,mBAAA;AAER,WAAA,iBAAiB,OAAO,GAAG;AAC1B,YAAA,SAAS,MAAM,KAAK,gBAAgB;AAC1C,uBAAiB,MAAM;AAGvB,iBAAWC,UAAS,QAAQ;AAE1B,cAAM,YAAY,qBAAqB,IAAIA,MAAK,KAAKA,OAAM;AAC3DA,eAAM,YAAY;AAClB,0BAAkBA,MAAK;AAAA,MAAA;AAIzB,iBAAWA,UAAS,QAAQ;AACpB,cAAA,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAEY,sCAAA,QAAQ,KAAKA,MAAK;AAChD,0BAAkB,WAAW;AAAA,MAAA;AAI/B,iBAAWA,UAAS,QAAQ;AACpB,cAAA,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,mBAAWD,YAAW,aAAa;AACjC,mCAAyBA,QAAO;AAAA,QAAA;AAAA,MAClC;AAAA,IACF;AAAA,EACF,UACA;AACe,mBAAA;AACf,kCAA8B,UAAU,CAAC;AACzC,yBAAqB,MAAM;AAAA,EAAA;AAE/B;AAEO,SAAS,MAAM,IAAgB;AACpC;AACI,MAAA;AACC,OAAA;AAAA,EAAA,UACH;AACA;AACA,QAAI,iBAAiB,GAAG;AACtB,YAAM,uBAAuB,MAAM,KAAK,gBAAgB,EAAE,CAAC;AAG3D,UAAI,sBAAsB;AACxB,gBAAQ,oBAAoB;AAAA,MAAA;AAAA,IAC9B;AAAA,EACF;AAEJ;;;;;;"}