@@ -5,34 +5,28 @@ let Effects: Computation[];
55let CurrentComputation : Computation ;
66
77export function effect < T > ( fn : ( ) => T ) {
8- const unsubscribe = ( ) => {
9- cleanupComputation ( effectComputation ) ;
10- unsubscribeChildEffect ( effectComputation ) ;
11- } ;
128 const effectComputation : Computation = {
139 state : ComputationState . STALE ,
1410 value : undefined ,
1511 compute ( ) {
1612 CurrentComputation = undefined ! ;
17- // removing the sources is made by `runComputation`.
18- unsubscribe ( ) ;
19- // reseting the context will be made by `runComputation`.
13+ // `removeSources` is made by `runComputation`.
14+ unsubscribeEffect ( effectComputation ) ;
2015 CurrentComputation = effectComputation ;
2116 return fn ( ) ;
2217 } ,
2318 sources : new Set ( ) ,
2419 childrenEffect : [ ] ,
2520 } ;
26- // Push to the parent effect if any
2721 CurrentComputation ?. childrenEffect ?. push ?.( effectComputation ) ;
28- runComputation ( effectComputation ) ;
22+ updateComputation ( effectComputation ) ;
2923
3024 // Remove sources and unsubscribe
3125 return ( ) => {
3226 removeSources ( effectComputation ) ;
3327 const currentComputation = CurrentComputation ;
3428 CurrentComputation = undefined ! ;
35- unsubscribe ( ) ;
29+ unsubscribeEffect ( effectComputation ) ;
3630 CurrentComputation = currentComputation ! ;
3731 } ;
3832}
@@ -51,7 +45,7 @@ export function derived<T>(fn: () => T): () => T {
5145 observers : new Set < Computation > ( ) ,
5246 } ;
5347 onDerived ?.( derivedComputation ) ;
54- runComputation ( derivedComputation ) ;
48+ updateComputation ( derivedComputation ) ;
5549 return derivedComputation . value ;
5650 } ;
5751}
@@ -61,9 +55,8 @@ export function onReadAtom(atom: Atom) {
6155 CurrentComputation . sources ! . add ( atom ) ;
6256 atom . observers . add ( CurrentComputation ) ;
6357}
64-
6558export function onWriteAtom ( atom : Atom ) {
66- runUpdates ( ( ) => {
59+ stackEffects ( ( ) => {
6760 for ( const ctx of atom . observers ) {
6861 if ( ctx . state === ComputationState . EXECUTED ) {
6962 ctx . state = ComputationState . STALE ;
@@ -74,14 +67,20 @@ export function onWriteAtom(atom: Atom) {
7467 } ) ;
7568 batchProcessEffects ( ) ;
7669}
70+ export function makeAtom ( ) : Atom {
71+ const atom : Atom = {
72+ value : undefined ,
73+ observers : new Set ( ) ,
74+ } ;
75+ return atom ;
76+ }
7777
7878export function getCurrentComputation ( ) {
7979 return CurrentComputation ;
8080}
8181export function setComputation ( computation : Computation ) {
8282 CurrentComputation = computation ;
8383}
84-
8584export function runWithComputation < T > ( computation : Computation , fn : ( ) => T ) : T {
8685 const currentComputation = CurrentComputation ;
8786 CurrentComputation = computation ;
@@ -93,45 +92,27 @@ export function runWithComputation<T>(computation: Computation, fn: () => T): T
9392 }
9493 return result ;
9594}
96-
9795export function withoutReactivity < T extends ( ...args : any [ ] ) => any > ( fn : T ) : ReturnType < T > {
9896 return runWithComputation ( undefined ! , fn ) ;
9997}
10098
101- export function makeAtom ( ) : Atom {
102- const atom : Atom = {
103- value : undefined ,
104- observers : new Set ( ) ,
105- } ;
106- return atom ;
107- }
108-
109- function runComputation ( computation : Computation ) {
99+ function updateComputation ( computation : Computation ) {
110100 const state = computation . state ;
111101 computation . isDerived && onReadAtom ( computation as Derived < any , any > ) ;
112102 if ( state === ComputationState . EXECUTED ) return ;
113103 if ( state === ComputationState . PENDING ) {
114104 computeSources ( computation as Derived < any , any > ) ;
115105 }
116- const executionContext = CurrentComputation ;
117106 // todo: test performance. We might want to avoid removing the atoms to
118107 // directly re-add them at compute. Especially as we are making them stale.
119108 removeSources ( computation ) ;
109+ const executionContext = CurrentComputation ;
120110 CurrentComputation = computation ;
121111 computation . value = computation . compute ?.( ) ;
122112 computation . state = ComputationState . EXECUTED ;
123113 CurrentComputation = executionContext ;
124114}
125115
126- const batchProcessEffects = batched ( processEffects ) ;
127- function processEffects ( ) {
128- if ( ! Effects ) return ;
129- for ( const computation of Effects ) {
130- runComputation ( computation ) ;
131- }
132- Effects = undefined ! ;
133- }
134-
135116function removeSources ( computation : Computation ) {
136117 const sources = computation . sources ;
137118 for ( const source of sources ) {
@@ -148,49 +129,62 @@ function removeSources(computation: Computation) {
148129 sources . clear ( ) ;
149130}
150131
132+ function stackEffects ( fn : Function ) {
133+ if ( Effects ) return fn ( ) ;
134+ Effects = [ ] ;
135+ try {
136+ return fn ( ) ;
137+ } finally {
138+ // processEffects();
139+ true ;
140+ }
141+ }
142+ const batchProcessEffects = batched ( processEffects ) ;
143+ function processEffects ( ) {
144+ if ( ! Effects ) return ;
145+ for ( const computation of Effects ) {
146+ updateComputation ( computation ) ;
147+ }
148+ Effects = undefined ! ;
149+ }
150+
151+ function unsubscribeEffect ( effectComputation : Computation ) {
152+ cleanupEffect ( effectComputation ) ;
153+ unsubscribeChildEffect ( effectComputation ) ;
154+ }
151155/**
152156 * Unsubscribe an execution context and all its children from all atoms
153157 * they are subscribed to.
154158 *
155- * @param parentExecutionContext the context to unsubscribe
159+ * @param parentEffect the context to unsubscribe
156160 */
157- function unsubscribeChildEffect ( parentExecutionContext : Computation ) {
158- for ( const children of parentExecutionContext . childrenEffect ! ) {
159- cleanupComputation ( children ) ;
161+ function unsubscribeChildEffect ( parentEffect : Computation ) {
162+ for ( const children of parentEffect . childrenEffect ! ) {
163+ cleanupEffect ( children ) ;
160164 removeSources ( children ) ;
161165 // Consider it executed to avoid it's re-execution
162166 children . state = ComputationState . EXECUTED ;
163167 unsubscribeChildEffect ( children ) ;
164168 }
165- parentExecutionContext . childrenEffect ! . length = 0 ;
169+ parentEffect . childrenEffect ! . length = 0 ;
166170}
167-
168- function cleanupComputation ( computation : Computation ) {
171+ function cleanupEffect ( computation : Computation ) {
169172 // the computation.value of an effect is a cleanup function
170- if ( computation . value && typeof computation . value === "function" ) {
171- computation . value ( ) ;
173+ const cleanupFn = computation . value ;
174+ if ( cleanupFn && typeof cleanupFn === "function" ) {
175+ cleanupFn ( ) ;
172176 computation . value = undefined ;
173177 }
174178}
175179
176- function runUpdates ( fn : Function ) {
177- if ( Effects ) return fn ( ) ;
178- Effects = [ ] ;
179- try {
180- return fn ( ) ;
181- } finally {
182- // processEffects();
183- true ;
184- }
185- }
186180function computeSources ( derived : Derived < any , any > ) {
187181 for ( const source of derived . sources ) {
188182 if ( "sources" in source ) continue ;
189- computeMemo ( source as Derived < any , any > ) ;
183+ computeDerived ( source as Derived < any , any > ) ;
190184 }
191185}
192186
193- function computeMemo ( derived : Derived < any , any > ) {
187+ function computeDerived ( derived : Derived < any , any > ) {
194188 if ( derived . state === ComputationState . EXECUTED ) {
195189 onReadAtom ( derived ) ;
196190 return derived . value ;
@@ -212,10 +206,10 @@ function markDownstream<A, B>(derived: Derived<A, B>) {
212206}
213207
214208// For tests
215- // todo: find a better way to test
209+
216210let onDerived : ( derived : Derived < any , any > ) => void ;
217211
218- export function setSginalHooks ( hooks : { onDerived : ( derived : Derived < any , any > ) => void } ) {
212+ export function setSignalHooks ( hooks : { onDerived : ( derived : Derived < any , any > ) => void } ) {
219213 if ( hooks . onDerived ) onDerived = hooks . onDerived ;
220214}
221215export function resetSignalHooks ( ) {
0 commit comments