You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I tried to re-implement our own Signal library on top of the current polyfill (v0.1.1). Our library is based on a two-phase push-only model with explicit dependency tracking. This is pretty much OK for static dependency graphs (our main applications/use cases). Effects are more or less the same as computed/derived signals, except that effects can be optionally disposed.
From my understanding
implementing push-only semantics (including effects) is not possible with the current proposal, let alone differences in runtime characteristics. Synchronous eager effects cannot be realized with Computed + Watcher.
Reasoning would be that since pulling signal values in watcher must be deferred to not read stale state, effects are inherently called asynchronous.
Thanks for your attention and please help me understand whether or not this presumption is correct.
Here is some complementary code to (maybe) better show what I'm trying to achieve.
importassertfrom'assert'import{SignalasPolyfill}from'signal-polyfill'importSignalfrom'@syncpoint/signal'const{ State, Computed }=Polyfillconst{ Watcher }=Polyfill.subtle// 'Simple' effect as proposed in different locations.// Don't care about clean-up for brevity.consteffect=callback=>{letbusy=falseconstwatcher=newWatcher(()=>{constpull=()=>{// Pulling immediately may result in stale state.watcher.getPending().forEach(s=>s.get())watcher.watch()// re-watchbusy=false}!busy&&(busy=true,queueMicrotask(pull))})constcomputed=newComputed(callback)watcher.watch(computed)computed.get()// pull immediately}describe('Polyfill',function(){it('async/effect',asyncfunction(){consta=newState(4)constacc=[]effect(()=>acc.push(a.get()))constcountdown=((n)=>setInterval(()=>n&&a.set(n--),0))countdown(3)awaitnewPromise(resolve=>setTimeout(resolve,10))assert.deepStrictEqual(acc,[4,3,2,1])//=> [PASS]})it('sync/effect [presumably impossible]',function(){consta=newState(4)constacc=[]effect(()=>acc.push(a.get()));[3,2,1].forEach(a.set.bind(a))// no time for watcher to kick inassert.deepStrictEqual(acc,[4,3,2,1])//=> [FAIL] actual: [4]})})describe('Signal',function(){it('on :: Signal s => (a -> *) -> s a -> (() -> Unit)',function(){consta=Signal.of(4)constacc=[]a.on(v=>acc.push(v))// eager, synchronous effect;[3,2,1].map(a)assert.deepStrictEqual(acc,[4,3,2,1])//=> [PASS]})it('scan :: Signal s => (b -> a -> b) -> b -> s a -> s b',function(){consta=Signal.of(4)constb=Signal.scan((acc,v)=>acc.concat(v),[],a);[3,2,1].map(a)assert.deepStrictEqual(b(),[4,3,2,1])//=> [PASS]})})
The text was updated successfully, but these errors were encountered:
I tried to re-implement our own Signal library on top of the current polyfill (v0.1.1). Our library is based on a two-phase push-only model with explicit dependency tracking. This is pretty much OK for static dependency graphs (our main applications/use cases). Effects are more or less the same as computed/derived signals, except that effects can be optionally disposed.
From my understanding
Reasoning would be that since pulling signal values in watcher must be deferred to not read stale state, effects are inherently called asynchronous.
Thanks for your attention and please help me understand whether or not this presumption is correct.
Here is some complementary code to (maybe) better show what I'm trying to achieve.
The text was updated successfully, but these errors were encountered: