@@ -16,7 +16,7 @@ import type {
1616 Test ,
1717 TestContext ,
1818} from './types/tasks'
19- import { getSafeTimers , shuffle } from '@vitest/utils'
19+ import { shuffle } from '@vitest/utils'
2020import { processError } from '@vitest/utils/error'
2121import { collectTests } from './collect'
2222import { PendingError } from './errors'
@@ -174,37 +174,53 @@ export async function callSuiteHook<T extends keyof SuiteHooks>(
174174
175175const packs = new Map < string , [ TaskResult | undefined , TaskMeta ] > ( )
176176const eventsPacks : [ string , TaskUpdateEvent ] [ ] = [ ]
177- let updateTimer : any
178- let previousUpdate : Promise < void > | undefined
179-
180- export function updateTask ( event : TaskUpdateEvent , task : Task , runner : VitestRunner ) : void {
181- eventsPacks . push ( [ task . id , event ] )
182- packs . set ( task . id , [ task . result , task . meta ] )
183-
184- const { clearTimeout, setTimeout } = getSafeTimers ( )
185-
186- clearTimeout ( updateTimer )
187- updateTimer = setTimeout ( ( ) => {
188- previousUpdate = sendTasksUpdate ( runner )
189- } , 10 )
190- }
191-
192- async function sendTasksUpdate ( runner : VitestRunner ) {
193- const { clearTimeout } = getSafeTimers ( )
194- clearTimeout ( updateTimer )
195- await previousUpdate
177+ const pendingTasksUpdates : Promise < void > [ ] = [ ]
196178
179+ function sendTasksUpdate ( runner : VitestRunner ) : void {
197180 if ( packs . size ) {
198181 const taskPacks = Array . from ( packs ) . map < TaskResultPack > ( ( [ id , task ] ) => {
199182 return [ id , task [ 0 ] , task [ 1 ] ]
200183 } )
201184 const p = runner . onTaskUpdate ?.( taskPacks , eventsPacks )
185+ if ( p ) {
186+ pendingTasksUpdates . push ( p )
187+ // remove successful promise to not grow array indefnitely,
188+ // but keep rejections so finishSendTasksUpdate can handle them
189+ p . then (
190+ ( ) => pendingTasksUpdates . splice ( pendingTasksUpdates . indexOf ( p ) , 1 ) ,
191+ ( ) => { } ,
192+ )
193+ }
202194 eventsPacks . length = 0
203195 packs . clear ( )
204- return p
205196 }
206197}
207198
199+ async function finishSendTasksUpdate ( runner : VitestRunner ) {
200+ sendTasksUpdate ( runner )
201+ await Promise . all ( pendingTasksUpdates )
202+ }
203+
204+ function throttle < T extends ( ...args : any [ ] ) => void > ( fn : T , ms : number ) : T {
205+ let last = 0
206+ return function ( this : any , ...args : any [ ] ) {
207+ const now = unixNow ( )
208+ if ( now - last > ms ) {
209+ last = now
210+ return fn . apply ( this , args )
211+ }
212+ } as any
213+ }
214+
215+ // throttle based on summary reporter's DURATION_UPDATE_INTERVAL_MS
216+ const sendTasksUpdateThrottled = throttle ( sendTasksUpdate , 100 )
217+
218+ export function updateTask ( event : TaskUpdateEvent , task : Task , runner : VitestRunner ) : void {
219+ eventsPacks . push ( [ task . id , event ] )
220+ packs . set ( task . id , [ task . result , task . meta ] )
221+ sendTasksUpdateThrottled ( runner )
222+ }
223+
208224async function callCleanupHooks ( cleanups : unknown [ ] ) {
209225 await Promise . all (
210226 cleanups . map ( async ( fn ) => {
@@ -561,7 +577,7 @@ export async function startTests(specs: string[] | FileSpecification[], runner:
561577
562578 await runner . onAfterRunFiles ?.( files )
563579
564- await sendTasksUpdate ( runner )
580+ await finishSendTasksUpdate ( runner )
565581
566582 return files
567583}
0 commit comments