@@ -16,17 +16,23 @@ export interface SchedulerJob {
16
16
cb ?: boolean
17
17
}
18
18
19
+ let isFlushing = false
20
+ let isFlushPending = false
21
+
19
22
const queue : ( SchedulerJob | null ) [ ] = [ ]
20
- const postFlushCbs : Function [ ] = [ ]
23
+ let flushIndex = 0
24
+
25
+ const pendingPreFlushCbs : Function [ ] = [ ]
26
+ let activePreFlushCbs : Function [ ] | null = null
27
+ let preFlushIndex = 0
28
+
29
+ const pendingPostFlushCbs : Function [ ] = [ ]
30
+ let activePostFlushCbs : Function [ ] | null = null
31
+ let postFlushIndex = 0
32
+
21
33
const resolvedPromise : Promise < any > = Promise . resolve ( )
22
34
let currentFlushPromise : Promise < void > | null = null
23
35
24
- let isFlushing = false
25
- let isFlushPending = false
26
- let flushIndex = 0
27
- let pendingPostFlushCbs : Function [ ] | null = null
28
- let pendingPostFlushIndex = 0
29
- let hasPendingPreFlushJobs = false
30
36
let currentPreFlushParentJob : SchedulerJob | null = null
31
37
32
38
const RECURSION_LIMIT = 100
@@ -53,90 +59,102 @@ export function queueJob(job: SchedulerJob) {
53
59
job !== currentPreFlushParentJob
54
60
) {
55
61
queue . push ( job )
56
- if ( ( job . id as number ) < 0 ) hasPendingPreFlushJobs = true
57
62
queueFlush ( )
58
63
}
59
64
}
60
65
66
+ function queueFlush ( ) {
67
+ if ( ! isFlushing && ! isFlushPending ) {
68
+ isFlushPending = true
69
+ currentFlushPromise = resolvedPromise . then ( flushJobs )
70
+ }
71
+ }
72
+
61
73
export function invalidateJob ( job : SchedulerJob ) {
62
74
const i = queue . indexOf ( job )
63
75
if ( i > - 1 ) {
64
76
queue [ i ] = null
65
77
}
66
78
}
67
79
68
- /**
69
- * Run flush: 'pre' watcher callbacks. This is only called in
70
- * `updateComponentPreRender` to cover the case where pre-flush watchers are
71
- * triggered by the change of a component's props. This means the scheduler is
72
- * already flushing and we are already inside the component's update effect,
73
- * right when the render function is about to be called. So if the watcher
74
- * triggers the same component to update, we don't want it to be queued (this
75
- * is checked via `currentPreFlushParentJob`).
76
- */
77
- export function runPreflushJobs ( parentJob : SchedulerJob ) {
78
- if ( hasPendingPreFlushJobs ) {
79
- currentPreFlushParentJob = parentJob
80
- hasPendingPreFlushJobs = false
81
- for ( let job , i = flushIndex + 1 ; i < queue . length ; i ++ ) {
82
- job = queue [ i ]
83
- if ( job && ( job . id as number ) < 0 ) {
84
- job ( )
85
- queue [ i ] = null
86
- }
87
- }
88
- currentPreFlushParentJob = null
89
- }
90
- }
91
-
92
- export function queuePostFlushCb ( cb : Function | Function [ ] ) {
80
+ function queueCb (
81
+ cb : Function | Function [ ] ,
82
+ activeQueue : Function [ ] | null ,
83
+ pendingQueue : Function [ ] ,
84
+ index : number
85
+ ) {
93
86
if ( ! isArray ( cb ) ) {
94
87
if (
95
- ! pendingPostFlushCbs ||
96
- ! pendingPostFlushCbs . includes (
97
- cb ,
98
- ( cb as SchedulerJob ) . cb
99
- ? pendingPostFlushIndex + 1
100
- : pendingPostFlushIndex
101
- )
88
+ ! activeQueue ||
89
+ ! activeQueue . includes ( cb , ( cb as SchedulerJob ) . cb ? index + 1 : index )
102
90
) {
103
- postFlushCbs . push ( cb )
91
+ pendingQueue . push ( cb )
104
92
}
105
93
} else {
106
94
// if cb is an array, it is a component lifecycle hook which can only be
107
95
// triggered by a job, which is already deduped in the main queue, so
108
96
// we can skip dupicate check here to improve perf
109
- postFlushCbs . push ( ...cb )
97
+ pendingQueue . push ( ...cb )
110
98
}
111
99
queueFlush ( )
112
100
}
113
101
114
- function queueFlush ( ) {
115
- if ( ! isFlushing && ! isFlushPending ) {
116
- isFlushPending = true
117
- currentFlushPromise = resolvedPromise . then ( flushJobs )
102
+ export function queuePreFlushCb ( cb : Function ) {
103
+ queueCb ( cb , activePreFlushCbs , pendingPreFlushCbs , preFlushIndex )
104
+ }
105
+
106
+ export function queuePostFlushCb ( cb : Function | Function [ ] ) {
107
+ queueCb ( cb , activePostFlushCbs , pendingPostFlushCbs , postFlushIndex )
108
+ }
109
+
110
+ export function flushPreFlushCbs (
111
+ seen ?: CountMap ,
112
+ parentJob : SchedulerJob | null = null
113
+ ) {
114
+ if ( pendingPreFlushCbs . length ) {
115
+ currentPreFlushParentJob = parentJob
116
+ activePreFlushCbs = [ ...new Set ( pendingPreFlushCbs ) ]
117
+ pendingPreFlushCbs . length = 0
118
+ if ( __DEV__ ) {
119
+ seen = seen || new Map ( )
120
+ }
121
+ for (
122
+ preFlushIndex = 0 ;
123
+ preFlushIndex < activePreFlushCbs . length ;
124
+ preFlushIndex ++
125
+ ) {
126
+ if ( __DEV__ ) {
127
+ checkRecursiveUpdates ( seen ! , activePreFlushCbs [ preFlushIndex ] )
128
+ }
129
+ activePreFlushCbs [ preFlushIndex ] ( )
130
+ }
131
+ activePreFlushCbs = null
132
+ preFlushIndex = 0
133
+ currentPreFlushParentJob = null
134
+ // recursively flush until it drains
135
+ flushPreFlushCbs ( seen , parentJob )
118
136
}
119
137
}
120
138
121
139
export function flushPostFlushCbs ( seen ?: CountMap ) {
122
- if ( postFlushCbs . length ) {
123
- pendingPostFlushCbs = [ ...new Set ( postFlushCbs ) ]
124
- postFlushCbs . length = 0
140
+ if ( pendingPostFlushCbs . length ) {
141
+ activePostFlushCbs = [ ...new Set ( pendingPostFlushCbs ) ]
142
+ pendingPostFlushCbs . length = 0
125
143
if ( __DEV__ ) {
126
144
seen = seen || new Map ( )
127
145
}
128
146
for (
129
- pendingPostFlushIndex = 0 ;
130
- pendingPostFlushIndex < pendingPostFlushCbs . length ;
131
- pendingPostFlushIndex ++
147
+ postFlushIndex = 0 ;
148
+ postFlushIndex < activePostFlushCbs . length ;
149
+ postFlushIndex ++
132
150
) {
133
151
if ( __DEV__ ) {
134
- checkRecursiveUpdates ( seen ! , pendingPostFlushCbs [ pendingPostFlushIndex ] )
152
+ checkRecursiveUpdates ( seen ! , activePostFlushCbs [ postFlushIndex ] )
135
153
}
136
- pendingPostFlushCbs [ pendingPostFlushIndex ] ( )
154
+ activePostFlushCbs [ postFlushIndex ] ( )
137
155
}
138
- pendingPostFlushCbs = null
139
- pendingPostFlushIndex = 0
156
+ activePostFlushCbs = null
157
+ postFlushIndex = 0
140
158
}
141
159
}
142
160
@@ -149,6 +167,8 @@ function flushJobs(seen?: CountMap) {
149
167
seen = seen || new Map ( )
150
168
}
151
169
170
+ flushPreFlushCbs ( seen )
171
+
152
172
// Sort queue before flush.
153
173
// This ensures that:
154
174
// 1. Components are updated from parent to child. (because parent is always
@@ -175,11 +195,12 @@ function flushJobs(seen?: CountMap) {
175
195
queue . length = 0
176
196
177
197
flushPostFlushCbs ( seen )
198
+
178
199
isFlushing = false
179
200
currentFlushPromise = null
180
201
// some postFlushCb queued jobs!
181
202
// keep flushing until it drains.
182
- if ( queue . length || postFlushCbs . length ) {
203
+ if ( queue . length || pendingPostFlushCbs . length ) {
183
204
flushJobs ( seen )
184
205
}
185
206
}
0 commit comments