@@ -112,12 +112,12 @@ type StoresValues<T> = T extends Readable<infer U> ? U :
112
112
* applying an aggregation function over its input values.
113
113
* @param {Stores } stores input stores
114
114
* @param {function(Stores=, function(*)=):* }fn function callback that aggregates the values
115
- * @param {*= }initial_value when used asynchronously
115
+ * @param {*= }value initial value, when used asynchronously
116
116
*/
117
117
export function derived < T , S extends Stores > (
118
118
stores : S ,
119
119
fn : ( values : StoresValues < S > , set ?: Subscriber < T > ) => T | Unsubscriber | void ,
120
- initial_value ?: T ,
120
+ value ?: T ,
121
121
) : Readable < T > {
122
122
123
123
const single = ! Array . isArray ( stores ) ;
@@ -127,12 +127,28 @@ export function derived<T, S extends Stores>(
127
127
128
128
const auto = fn . length < 2 ;
129
129
130
- return readable ( initial_value , ( set ) => {
131
- let inited = false ;
130
+ const subscribers : Array < SubscribeInvalidateTuple < T > > = [ ] ;
131
+ let unsubscribers ;
132
+ let cleanup = noop ;
133
+ let running = false ;
134
+
135
+ function invalidate ( ) {
136
+ subscribers . forEach ( subscriber => subscriber [ 1 ] ( ) ) ;
137
+ }
138
+
139
+ function set ( current_value ) {
140
+ value = current_value ;
141
+ if ( running ) {
142
+ invalidate ( ) ;
143
+ subscribers . forEach ( subscriber => subscriber [ 0 ] ( value ) ) ;
144
+ }
145
+ }
146
+
147
+ function start ( ) {
132
148
const values : StoresValues < S > = [ ] as StoresValues < S > ;
133
149
134
150
let pending = 0 ;
135
- let cleanup = noop ;
151
+ running = false ;
136
152
137
153
const sync = ( ) => {
138
154
if ( pending ) {
@@ -147,27 +163,47 @@ export function derived<T, S extends Stores>(
147
163
}
148
164
} ;
149
165
150
- const unsubscribers = stores_array . map ( ( store , i ) => store . subscribe (
166
+ unsubscribers = stores_array . map ( ( store , i ) => store . subscribe (
151
167
( value ) => {
152
168
values [ i ] = value ;
153
169
pending &= ~ ( 1 << i ) ;
154
- if ( inited ) {
170
+ if ( running ) {
155
171
sync ( ) ;
156
172
}
157
173
} ,
158
174
( ) => {
175
+ invalidate ( ) ;
159
176
pending |= ( 1 << i ) ;
160
177
} ) ,
161
178
) ;
162
179
163
- inited = true ;
164
180
sync ( ) ;
181
+ running = true ;
182
+ }
165
183
166
- return function stop ( ) {
167
- run_all ( unsubscribers ) ;
168
- cleanup ( ) ;
169
- } ;
170
- } ) ;
184
+ function stop ( ) {
185
+ run_all ( unsubscribers ) ;
186
+ cleanup ( ) ;
187
+ }
188
+
189
+ return {
190
+ subscribe ( run : Subscriber < T > , invalidate : Invalidater < T > = noop ) : Unsubscriber {
191
+ const subscriber : SubscribeInvalidateTuple < T > = [ run , invalidate ] ;
192
+ subscribers . push ( subscriber ) ;
193
+ if ( subscribers . length === 1 ) start ( ) ;
194
+ run ( value ) ;
195
+
196
+ return ( ) => {
197
+ const index = subscribers . indexOf ( subscriber ) ;
198
+ if ( index !== - 1 ) {
199
+ subscribers . splice ( index , 1 ) ;
200
+ }
201
+ if ( subscribers . length === 0 ) {
202
+ stop ( ) ;
203
+ }
204
+ } ;
205
+ }
206
+ } ;
171
207
}
172
208
173
209
/**
0 commit comments