@@ -22,25 +22,33 @@ export interface Link {
22
22
nextSub : Link | undefined
23
23
prevDep : Link | undefined
24
24
nextDep : Link | undefined
25
+ nextJob : Link | undefined
25
26
}
26
27
27
28
export const enum SubscriberFlags {
28
29
Tracking = 1 << 2 ,
29
30
Recursed = 1 << 4 ,
30
31
Dirty = 1 << 5 ,
31
32
Pending = 1 << 6 ,
33
+ Job = 1 << 10 ,
32
34
}
33
35
34
36
interface OneWayLink < T > {
35
37
target : T
36
38
linked : OneWayLink < T > | undefined
37
39
}
38
40
39
- const notifyBuffer : ( Effect | EffectScope | undefined ) [ ] = [ ]
41
+ const notifyBuffer : ( Effect | undefined ) [ ] = [ ]
42
+ const jobBuffer : ( Effect | EffectScope | undefined ) [ ] = [ ]
40
43
41
44
let batchDepth = 0
42
45
let notifyIndex = 0
46
+ let flushIndex = 0
43
47
let notifyBufferLength = 0
48
+ let jobBufferLength = 0
49
+ let currentFlushPromise : Promise < void > | undefined
50
+
51
+ const resolvedPromise = /*@__PURE__ */ Promise . resolve ( ) as Promise < any >
44
52
45
53
export function startBatch ( ) : void {
46
54
++ batchDepth
@@ -77,6 +85,7 @@ export function link(dep: Dependency, sub: Subscriber): void {
77
85
nextDep,
78
86
prevSub : undefined ,
79
87
nextSub : undefined ,
88
+ nextJob : undefined ,
80
89
}
81
90
if ( prevDep === undefined ) {
82
91
sub . deps = newLink
@@ -180,18 +189,33 @@ export function propagate(current: Link): void {
180
189
181
190
if ( shouldNotify ) {
182
191
if ( shouldNotify === 1 && 'notify' in sub ) {
183
- notifyBuffer [ notifyBufferLength ++ ] = sub
184
- } else {
185
- const subSubs = ( sub as Dependency ) . subs
186
- if ( subSubs !== undefined ) {
187
- current = subSubs
188
- if ( subSubs . nextSub !== undefined ) {
189
- branchs = { target : next , linked : branchs }
190
- ++ branchDepth
191
- next = current . nextSub
192
+ if ( subFlags & SubscriberFlags . Job ) {
193
+ let last = sub
194
+ let parent = sub . subs
195
+ let queued = false
196
+ while ( parent !== undefined ) {
197
+ last = parent . sub as EffectScope
198
+ let next = last . subs
199
+ while ( last . deps === last . depsTail && next !== undefined ) {
200
+ last = next . sub as EffectScope
201
+ next = last . subs
202
+ }
203
+ const jobsTail = last . jobsTail
204
+ if ( jobsTail === undefined ) {
205
+ last . jobsTail = last . jobs = parent
206
+ parent = next
207
+ } else {
208
+ last . jobsTail = jobsTail . nextJob = parent
209
+ queued = true
210
+ break
211
+ }
192
212
}
193
- targetFlag = SubscriberFlags . Pending
194
- continue
213
+ if ( ! queued ) {
214
+ jobBuffer [ jobBufferLength ++ ] = last
215
+ queueFlush ( )
216
+ }
217
+ } else if ( ! ( 'jobs' in sub ) ) {
218
+ notifyBuffer [ notifyBufferLength ++ ] = sub
195
219
}
196
220
}
197
221
} else if ( ! ( subFlags & ( SubscriberFlags . Tracking | targetFlag ) ) ) {
@@ -230,6 +254,24 @@ export function propagate(current: Link): void {
230
254
}
231
255
}
232
256
257
+ async function queueFlush ( ) {
258
+ if ( currentFlushPromise === undefined ) {
259
+ currentFlushPromise = resolvedPromise
260
+ try {
261
+ await currentFlushPromise
262
+ while ( flushIndex < jobBufferLength ) {
263
+ const effect = jobBuffer [ flushIndex ] !
264
+ jobBuffer [ flushIndex ++ ] = undefined
265
+ effect . notify ( )
266
+ }
267
+ flushIndex = 0
268
+ jobBufferLength = 0
269
+ } finally {
270
+ currentFlushPromise = undefined
271
+ }
272
+ }
273
+ }
274
+
233
275
export function startTracking ( sub : Subscriber ) : void {
234
276
sub . depsTail = undefined
235
277
sub . flags =
0 commit comments