@@ -72,6 +72,11 @@ describe('batchUpdater', () => {
7272 } )
7373
7474 it ( 'should batch multiple updates together' , ( ) => {
75+ // 标记这些类为已渲染,这样它们就不会被立即执行
76+ batchUpdater . markAsRendered ( 'class1' )
77+ batchUpdater . markAsRendered ( 'class2' )
78+ batchUpdater . markAsRendered ( 'class3' )
79+
7580 batchUpdater . scheduleUpdate ( 'class1' , '.class1 { color: red; }' )
7681 batchUpdater . scheduleUpdate ( 'class2' , '.class2 { color: blue; }' )
7782 batchUpdater . scheduleUpdate ( 'class3' , '.class3 { color: green; }' )
@@ -87,6 +92,10 @@ describe('batchUpdater', () => {
8792 } )
8893
8994 it ( 'should replace duplicate class updates' , ( ) => {
95+ // 标记类为已渲染,这样更新会被批量处理
96+ batchUpdater . markAsRendered ( 'test-class' )
97+ batchUpdater . markAsRendered ( 'other-class' )
98+
9099 batchUpdater . scheduleUpdate ( 'test-class' , '.test { color: red; }' )
91100 batchUpdater . scheduleUpdate ( 'test-class' , '.test { color: blue; }' ) // 应该替换前一个
92101 batchUpdater . scheduleUpdate ( 'other-class' , '.other { color: green; }' )
@@ -102,6 +111,11 @@ describe('batchUpdater', () => {
102111 } )
103112
104113 it ( 'should handle priority ordering' , ( ) => {
114+ // 标记类为已渲染,这样更新会被批量处理
115+ batchUpdater . markAsRendered ( 'low-priority' )
116+ batchUpdater . markAsRendered ( 'high-priority' )
117+ batchUpdater . markAsRendered ( 'medium-priority' )
118+
105119 batchUpdater . scheduleUpdate ( 'low-priority' , '.low { color: red; }' , 1 )
106120 batchUpdater . scheduleUpdate ( 'high-priority' , '.high { color: blue; }' , 10 )
107121 batchUpdater . scheduleUpdate ( 'medium-priority' , '.medium { color: green; }' , 5 )
@@ -281,6 +295,10 @@ describe('batchUpdater', () => {
281295 vi . useFakeTimers ( )
282296 configureStyleProcessing ( { enableBatchUpdates : true } )
283297
298+ // 标记类为已渲染,这样更新会被批量处理
299+ batchUpdater . markAsRendered ( 'low' )
300+ batchUpdater . markAsRendered ( 'high' )
301+
284302 batchUpdater . scheduleUpdate ( 'low' , '.low { color: red; }' , - 1 )
285303 batchUpdater . scheduleUpdate ( 'high' , '.high { color: blue; }' , 1 )
286304
@@ -319,4 +337,112 @@ describe('batchUpdater', () => {
319337 expect ( mockInsertFunction ) . not . toHaveBeenCalled ( )
320338 } )
321339 } )
340+
341+ describe ( 'first render optimization' , ( ) => {
342+ beforeEach ( ( ) => {
343+ vi . useFakeTimers ( )
344+ configureStyleProcessing ( { enableBatchUpdates : true , batchDelay : 16 } )
345+ batchUpdater . resetFirstRenderState ( )
346+ } )
347+
348+ it ( 'should execute first render styles immediately even with batch updates enabled' , ( ) => {
349+ batchUpdater . scheduleUpdate ( 'first-render-class' , '.first { color: red; }' )
350+
351+ // 首次渲染应该立即执行,不需要等待
352+ expect ( mockInsertFunction ) . toHaveBeenCalledWith ( 'first-render-class' , '.first { color: red; }' )
353+ expect ( batchUpdater . getPendingCount ( ) ) . toBe ( 0 )
354+ } )
355+
356+ it ( 'should batch subsequent updates for the same class' , ( ) => {
357+ // 首次渲染
358+ batchUpdater . scheduleUpdate ( 'test-class' , '.test { color: red; }' )
359+ expect ( mockInsertFunction ) . toHaveBeenCalledTimes ( 1 )
360+
361+ // 后续更新应该被批量处理
362+ batchUpdater . scheduleUpdate ( 'test-class' , '.test { color: blue; }' )
363+ expect ( mockInsertFunction ) . toHaveBeenCalledTimes ( 1 ) // 仍然是1次
364+ expect ( batchUpdater . getPendingCount ( ) ) . toBe ( 1 )
365+
366+ // 等待批量更新执行
367+ vi . advanceTimersByTime ( 16 )
368+ vi . runAllTimers ( )
369+
370+ expect ( mockInsertFunction ) . toHaveBeenCalledTimes ( 2 )
371+ expect ( mockInsertFunction ) . toHaveBeenLastCalledWith ( 'test-class' , '.test { color: blue; }' )
372+ } )
373+
374+ it ( 'should prioritize first render styles in batch updates' , ( ) => {
375+ // 先添加一个已渲染的类的更新
376+ batchUpdater . markAsRendered ( 'already-rendered' )
377+ batchUpdater . scheduleUpdate ( 'already-rendered' , '.already { color: green; }' )
378+
379+ // 再添加一个首次渲染的类
380+ batchUpdater . resetFirstRenderState ( )
381+ batchUpdater . scheduleUpdate ( 'first-render' , '.first { color: red; }' )
382+
383+ // 首次渲染应该立即执行
384+ expect ( mockInsertFunction ) . toHaveBeenCalledWith ( 'first-render' , '.first { color: red; }' )
385+
386+ // 等待批量更新执行已渲染的类
387+ vi . advanceTimersByTime ( 16 )
388+ vi . runAllTimers ( )
389+
390+ expect ( mockInsertFunction ) . toHaveBeenCalledWith ( 'already-rendered' , '.already { color: green; }' )
391+ } )
392+
393+ it ( 'should track rendered classes correctly' , ( ) => {
394+ expect ( batchUpdater . isFirstRender ( 'new-class' ) ) . toBe ( true )
395+
396+ batchUpdater . scheduleUpdate ( 'new-class' , '.new { color: red; }' )
397+
398+ expect ( batchUpdater . isFirstRender ( 'new-class' ) ) . toBe ( false )
399+ } )
400+
401+ it ( 'should allow manual marking of rendered classes' , ( ) => {
402+ expect ( batchUpdater . isFirstRender ( 'manual-class' ) ) . toBe ( true )
403+
404+ batchUpdater . markAsRendered ( 'manual-class' )
405+
406+ expect ( batchUpdater . isFirstRender ( 'manual-class' ) ) . toBe ( false )
407+
408+ // 现在这个类的更新应该被批量处理
409+ batchUpdater . scheduleUpdate ( 'manual-class' , '.manual { color: red; }' )
410+ expect ( mockInsertFunction ) . not . toHaveBeenCalled ( )
411+ expect ( batchUpdater . getPendingCount ( ) ) . toBe ( 1 )
412+ } )
413+
414+ it ( 'should reset first render state correctly' , ( ) => {
415+ batchUpdater . scheduleUpdate ( 'test-class' , '.test { color: red; }' )
416+ expect ( batchUpdater . isFirstRender ( 'test-class' ) ) . toBe ( false )
417+
418+ batchUpdater . resetFirstRenderState ( )
419+ expect ( batchUpdater . isFirstRender ( 'test-class' ) ) . toBe ( true )
420+
421+ // 重置后,相同类名的更新应该被视为首次渲染
422+ batchUpdater . scheduleUpdate ( 'test-class' , '.test { color: blue; }' )
423+ expect ( mockInsertFunction ) . toHaveBeenCalledWith ( 'test-class' , '.test { color: blue; }' )
424+ } )
425+
426+ it ( 'should handle multiple first render classes simultaneously' , ( ) => {
427+ batchUpdater . scheduleUpdate ( 'class1' , '.class1 { color: red; }' )
428+ batchUpdater . scheduleUpdate ( 'class2' , '.class2 { color: blue; }' )
429+ batchUpdater . scheduleUpdate ( 'class3' , '.class3 { color: green; }' )
430+
431+ // 所有首次渲染的类都应该立即执行
432+ expect ( mockInsertFunction ) . toHaveBeenCalledTimes ( 3 )
433+ expect ( mockInsertFunction ) . toHaveBeenNthCalledWith ( 1 , 'class1' , '.class1 { color: red; }' )
434+ expect ( mockInsertFunction ) . toHaveBeenNthCalledWith ( 2 , 'class2' , '.class2 { color: blue; }' )
435+ expect ( mockInsertFunction ) . toHaveBeenNthCalledWith ( 3 , 'class3' , '.class3 { color: green; }' )
436+ expect ( batchUpdater . getPendingCount ( ) ) . toBe ( 0 )
437+ } )
438+
439+ it ( 'should respect batch updates disabled setting for first render' , ( ) => {
440+ configureStyleProcessing ( { enableBatchUpdates : false } )
441+
442+ batchUpdater . scheduleUpdate ( 'test-class' , '.test { color: red; }' )
443+
444+ expect ( mockInsertFunction ) . toHaveBeenCalledWith ( 'test-class' , '.test { color: red; }' )
445+ expect ( batchUpdater . getPendingCount ( ) ) . toBe ( 0 )
446+ } )
447+ } )
322448} )
0 commit comments