1- import { ErrorCodes , callWithErrorHandling , handleError } from './errorHandling'
1+ import { ErrorCodes , handleError } from './errorHandling'
22import { isArray } from '@vue/shared'
33import { type GenericComponentInstance , getComponentName } from './component'
44
@@ -39,23 +39,21 @@ export interface SchedulerJob extends Function {
3939
4040export type SchedulerJobs = SchedulerJob | SchedulerJob [ ]
4141
42- const queueMainJobs : ( SchedulerJob | undefined ) [ ] = [ ]
43- const queuePreJobs : ( SchedulerJob | undefined ) [ ] = [ ]
44- const queuePostJobs : ( SchedulerJob | undefined ) [ ] = [ ]
42+ const jobs : SchedulerJob [ ] = [ ]
43+ const preJobs : SchedulerJob [ ] = [ ]
4544
46- let mainFlushIndex = - 1
47- let preFlushIndex = - 1
48- let postFlushIndex = 0
49- let mainJobsLength = 0
50- let preJobsLength = 0
51- let postJobsLength = 0
52- let flushingPreJob = false
53- let activePostFlushCbs : SchedulerJob [ ] | null = null
45+ let postJobs : SchedulerJob [ ] = [ ]
46+ let activePostJobs : SchedulerJob [ ] | null = null
5447let currentFlushPromise : Promise < void > | null = null
48+ let jobsLength = 0
49+ let preJobsLength = 0
50+ let flushIndex = 0
51+ let preFlushIndex = 0
52+ let postFlushIndex = 0
5553
5654const resolvedPromise = /*@__PURE__ */ Promise . resolve ( ) as Promise < any >
57-
5855const RECURSION_LIMIT = 100
56+
5957type CountMap = Map < SchedulerJob , number >
6058
6159export function nextTick < T = void , R = void > (
@@ -75,48 +73,70 @@ export function nextTick<T = void, R = void>(
7573// A pre watcher will have the same id as its component's update job. The
7674// watcher should be inserted immediately before the update job. This allows
7775// watchers to be skipped if the component is unmounted by the parent update.
78- function findInsertionIndex ( id : number , isPre : boolean ) {
79- let start = ( isPre ? preFlushIndex : mainFlushIndex ) + 1
80- let end = isPre ? preJobsLength : mainJobsLength
81- const queue = isPre ? queuePreJobs : queueMainJobs
82-
76+ function findInsertionIndex (
77+ id : number ,
78+ queue : SchedulerJob [ ] ,
79+ start : number ,
80+ end : number ,
81+ ) {
8382 while ( start < end ) {
8483 const middle = ( start + end ) >>> 1
85- const middleJob = queue [ middle ] !
84+ const middleJob = queue [ middle ]
8685 if ( middleJob . id ! <= id ) {
8786 start = middle + 1
8887 } else {
8988 end = middle
9089 }
9190 }
92-
9391 return start
9492}
9593
9694/**
9795 * @internal for runtime-vapor only
9896 */
9997export function queueJob ( job : SchedulerJob , isPre = false ) : void {
98+ if ( isPre ) {
99+ if ( _queueJob ( job , preJobs , preJobsLength , preFlushIndex , - 1 ) ) {
100+ preJobsLength ++
101+ queueFlush ( )
102+ }
103+ } else {
104+ if ( _queueJob ( job , jobs , jobsLength , flushIndex , Infinity ) ) {
105+ jobsLength ++
106+ queueFlush ( )
107+ }
108+ }
109+ }
110+
111+ function _queueJob (
112+ job : SchedulerJob ,
113+ queue : SchedulerJob [ ] ,
114+ length : number ,
115+ flushIndex : number ,
116+ defaultId : number ,
117+ ) {
100118 const flags = job . flags !
101119 if ( ! ( flags & SchedulerJobFlags . QUEUED ) ) {
120+ job . flags ! = flags | SchedulerJobFlags . QUEUED
102121 if ( job . id === undefined ) {
103- job . id = isPre ? - 1 : Infinity
122+ job . id = defaultId
104123 }
105- const queueLength = isPre ? preJobsLength : mainJobsLength
106- const queue = isPre ? queuePreJobs : queueMainJobs
107124 if (
108- ! queueLength ||
125+ flushIndex === length ||
109126 // fast path when the job id is larger than the tail
110- job . id >= queue [ queueLength - 1 ] ! . id !
127+ job . id >= queue [ length - 1 ] . id !
111128 ) {
112- queue [ queueLength ] = job
129+ queue [ length ] = job
113130 } else {
114- queue . splice ( findInsertionIndex ( job . id , isPre ) , 0 , job )
131+ queue . splice (
132+ findInsertionIndex ( job . id , queue , flushIndex , length ) ,
133+ 0 ,
134+ job ,
135+ )
115136 }
116- isPre ? preJobsLength ++ : mainJobsLength ++
117- job . flags ! = flags | SchedulerJobFlags . QUEUED
118- queueFlush ( )
137+ return true
119138 }
139+ return false
120140}
121141
122142function queueFlush ( ) {
@@ -128,26 +148,19 @@ function queueFlush() {
128148 }
129149}
130150
131- export function queuePostFlushCb ( cb : SchedulerJobs ) : void {
132- if ( ! isArray ( cb ) ) {
133- if ( cb . id === undefined ) {
134- cb . id = Infinity
135- }
136- if ( activePostFlushCbs && cb . id === - 1 ) {
137- activePostFlushCbs . splice ( postFlushIndex + 1 , 0 , cb )
138- } else if ( ! ( cb . flags ! & SchedulerJobFlags . QUEUED ) ) {
139- queuePostJobs [ postJobsLength ++ ] = cb
140- cb . flags ! |= SchedulerJobFlags . QUEUED
151+ export function queuePostFlushCb ( jobs : SchedulerJobs ) : void {
152+ if ( ! isArray ( jobs ) ) {
153+ if ( activePostJobs && jobs . id === - 1 ) {
154+ activePostJobs . splice ( postFlushIndex , 0 , jobs )
155+ } else {
156+ _queueJob ( jobs , postJobs , postJobs . length , 0 , Infinity )
141157 }
142158 } else {
143159 // if cb is an array, it is a component lifecycle hook which can only be
144160 // triggered by a job, which is already deduped in the main queue, so
145161 // we can skip duplicate check here to improve perf
146- for ( const job of cb ) {
147- if ( job . id === undefined ) {
148- job . id = Infinity
149- }
150- queuePostJobs [ postJobsLength ++ ] = job
162+ for ( const job of jobs ) {
163+ _queueJob ( job , postJobs , postJobs . length , 0 , Infinity )
151164 }
152165 }
153166 queueFlush ( )
@@ -160,62 +173,45 @@ export function flushPreFlushCbs(
160173 if ( __DEV__ ) {
161174 seen = seen || new Map ( )
162175 }
163- for (
164- let i = flushingPreJob ? preFlushIndex + 1 : preFlushIndex ;
165- i < preJobsLength ;
166- i ++
167- ) {
168- const cb = queuePreJobs [ i ]
169- if ( cb ) {
170- if ( instance && cb . id !== instance . uid ) {
171- continue
172- }
173- if ( __DEV__ && checkRecursiveUpdates ( seen ! , cb ) ) {
174- continue
175- }
176- queuePreJobs . splice ( i , 1 )
177- preJobsLength --
178- i --
179- if ( cb . flags ! & SchedulerJobFlags . ALLOW_RECURSE ) {
180- cb . flags ! &= ~ SchedulerJobFlags . QUEUED
181- }
182- cb ( )
183- if ( ! ( cb . flags ! & SchedulerJobFlags . ALLOW_RECURSE ) ) {
184- cb . flags ! &= ~ SchedulerJobFlags . QUEUED
185- }
176+ for ( let i = preFlushIndex ; i < preJobsLength ; i ++ ) {
177+ const cb = preJobs [ i ]
178+ if ( instance && cb . id !== instance . uid ) {
179+ continue
180+ }
181+ if ( __DEV__ && checkRecursiveUpdates ( seen ! , cb ) ) {
182+ continue
183+ }
184+ preJobs . splice ( i , 1 )
185+ i --
186+ preJobsLength --
187+ if ( cb . flags ! & SchedulerJobFlags . ALLOW_RECURSE ) {
188+ cb . flags ! &= ~ SchedulerJobFlags . QUEUED
189+ }
190+ cb ( )
191+ if ( ! ( cb . flags ! & SchedulerJobFlags . ALLOW_RECURSE ) ) {
192+ cb . flags ! &= ~ SchedulerJobFlags . QUEUED
186193 }
187194 }
188195}
189196
190197export function flushPostFlushCbs ( seen ?: CountMap ) : void {
191- if ( postJobsLength ) {
192- const deduped = new Set < SchedulerJob > ( )
193- for ( let i = 0 ; i < postJobsLength ; i ++ ) {
194- const job = queuePostJobs [ i ] !
195- queuePostJobs [ i ] = undefined
196- deduped . add ( job )
197- }
198- postJobsLength = 0
199-
200- const sorted = [ ...deduped ] . sort ( ( a , b ) => a . id ! - b . id ! )
201-
198+ if ( postJobs . length ) {
202199 // #1947 already has active queue, nested flushPostFlushCbs call
203- if ( activePostFlushCbs ) {
204- activePostFlushCbs . push ( ...sorted )
200+ if ( activePostJobs ) {
201+ activePostJobs . push ( ...postJobs )
202+ postJobs . length = 0
205203 return
206204 }
207205
208- activePostFlushCbs = sorted
206+ activePostJobs = postJobs
207+ postJobs = [ ]
208+
209209 if ( __DEV__ ) {
210210 seen = seen || new Map ( )
211211 }
212212
213- for (
214- postFlushIndex = 0 ;
215- postFlushIndex < activePostFlushCbs . length ;
216- postFlushIndex ++
217- ) {
218- const cb = activePostFlushCbs [ postFlushIndex ]
213+ while ( postFlushIndex < activePostJobs . length ) {
214+ const cb = activePostJobs [ postFlushIndex ++ ]
219215 if ( __DEV__ && checkRecursiveUpdates ( seen ! , cb ) ) {
220216 continue
221217 }
@@ -230,7 +226,8 @@ export function flushPostFlushCbs(seen?: CountMap): void {
230226 }
231227 }
232228 }
233- activePostFlushCbs = null
229+
230+ activePostJobs = null
234231 postFlushIndex = 0
235232 }
236233}
@@ -250,33 +247,30 @@ export function flushOnAppMount(): void {
250247
251248function flushJobs ( seen ?: CountMap ) {
252249 if ( __DEV__ ) {
253- seen = seen || new Map ( )
250+ seen ||= new Map ( )
254251 }
255252
256253 try {
257- preFlushIndex = 0
258- mainFlushIndex = 0
259-
260- while ( preFlushIndex < preJobsLength || mainFlushIndex < mainJobsLength ) {
254+ while ( preFlushIndex < preJobsLength || flushIndex < jobsLength ) {
261255 let job : SchedulerJob
262256 if ( preFlushIndex < preJobsLength ) {
263- if ( mainFlushIndex < mainJobsLength ) {
264- const preJob = queuePreJobs [ preFlushIndex ] !
265- const mainJob = queueMainJobs [ mainFlushIndex ] !
257+ if ( flushIndex < jobsLength ) {
258+ const mainJob = jobs [ flushIndex ]
259+ const preJob = preJobs [ preFlushIndex ]
266260 if ( preJob . id ! <= mainJob . id ! ) {
267261 job = preJob
268- flushingPreJob = true
262+ preJobs [ preFlushIndex ++ ] = undefined as any
269263 } else {
270264 job = mainJob
271- flushingPreJob = false
265+ jobs [ flushIndex ++ ] = undefined as any
272266 }
273267 } else {
274- job = queuePreJobs [ preFlushIndex ] !
275- flushingPreJob = true
268+ job = preJobs [ preFlushIndex ]
269+ preJobs [ preFlushIndex ++ ] = undefined as any
276270 }
277271 } else {
278- job = queueMainJobs [ mainFlushIndex ] !
279- flushingPreJob = false
272+ job = jobs [ flushIndex ]
273+ jobs [ flushIndex ++ ] = undefined as any
280274 }
281275
282276 if ( ! ( job . flags ! & SchedulerJobFlags . DISPOSED ) ) {
@@ -286,60 +280,47 @@ function flushJobs(seen?: CountMap) {
286280 // they would get eventually shaken by a minifier like terser, some minifiers
287281 // would fail to do that (e.g. https://github.com/evanw/esbuild/issues/1610)
288282 if ( __DEV__ && checkRecursiveUpdates ( seen ! , job ) ) {
289- if ( flushingPreJob ) {
290- queuePreJobs [ preFlushIndex ++ ] = undefined
291- } else {
292- queueMainJobs [ mainFlushIndex ++ ] = undefined
293- }
294283 continue
295284 }
296285 if ( job . flags ! & SchedulerJobFlags . ALLOW_RECURSE ) {
297286 job . flags ! &= ~ SchedulerJobFlags . QUEUED
298287 }
299- callWithErrorHandling (
300- job ,
301- job . i ,
302- job . i ? ErrorCodes . COMPONENT_UPDATE : ErrorCodes . SCHEDULER ,
303- )
304- if ( ! ( job . flags ! & SchedulerJobFlags . ALLOW_RECURSE ) ) {
305- job . flags ! &= ~ SchedulerJobFlags . QUEUED
288+ try {
289+ job ( )
290+ } catch ( err ) {
291+ handleError (
292+ err ,
293+ job . i ,
294+ job . i ? ErrorCodes . COMPONENT_UPDATE : ErrorCodes . SCHEDULER ,
295+ )
296+ } finally {
297+ if ( ! ( job . flags ! & SchedulerJobFlags . ALLOW_RECURSE ) ) {
298+ job . flags ! &= ~ SchedulerJobFlags . QUEUED
299+ }
306300 }
307301 }
308-
309- if ( flushingPreJob ) {
310- queuePreJobs [ preFlushIndex ++ ] = undefined
311- } else {
312- queueMainJobs [ mainFlushIndex ++ ] = undefined
313- }
314302 }
315303 } finally {
316304 // If there was an error we still need to clear the QUEUED flags
317305 while ( preFlushIndex < preJobsLength ) {
318- const job = queuePreJobs [ preFlushIndex ]
319- queuePreJobs [ preFlushIndex ++ ] = undefined
320- if ( job ) {
321- job . flags ! &= ~ SchedulerJobFlags . QUEUED
322- }
306+ preJobs [ preFlushIndex ] . flags ! &= ~ SchedulerJobFlags . QUEUED
307+ preJobs [ preFlushIndex ++ ] = undefined as any
323308 }
324- while ( mainFlushIndex < mainJobsLength ) {
325- const job = queueMainJobs [ mainFlushIndex ]
326- queueMainJobs [ mainFlushIndex ++ ] = undefined
327- if ( job ) {
328- job . flags ! &= ~ SchedulerJobFlags . QUEUED
329- }
309+ while ( flushIndex < jobsLength ) {
310+ jobs [ flushIndex ] . flags ! &= ~ SchedulerJobFlags . QUEUED
311+ jobs [ flushIndex ++ ] = undefined as any
330312 }
331313
332- preFlushIndex = - 1
333- mainFlushIndex = - 1
314+ flushIndex = 0
315+ preFlushIndex = 0
316+ jobsLength = 0
334317 preJobsLength = 0
335- mainJobsLength = 0
336- flushingPreJob = false
337318
338319 flushPostFlushCbs ( seen )
339320
340321 currentFlushPromise = null
341322 // If new jobs have been added to either queue, keep flushing
342- if ( preJobsLength || mainJobsLength || postJobsLength ) {
323+ if ( preJobsLength || jobsLength || postJobs . length ) {
343324 flushJobs ( seen )
344325 }
345326 }
0 commit comments