@@ -534,13 +534,13 @@ if (typeof window !== 'undefined' && window._schedMock) {
534
534
}
535
535
}
536
536
537
- var scheduledCallback = null ;
538
- var isIdleScheduled = false ;
537
+ var scheduledHostCallback = null ;
538
+ var isMessageEventScheduled = false ;
539
539
var timeoutTime = - 1 ;
540
540
541
541
var isAnimationFrameScheduled = false ;
542
542
543
- var isPerformingIdleWork = false ;
543
+ var isFlushingHostCallback = false ;
544
544
545
545
var frameDeadline = 0 ;
546
546
// We start out assuming that we run at 30fps but then the heuristic tracking
@@ -564,15 +564,20 @@ if (typeof window !== 'undefined' && window._schedMock) {
564
564
return ;
565
565
}
566
566
567
- isIdleScheduled = false ;
567
+ isMessageEventScheduled = false ;
568
+
569
+ var prevScheduledCallback = scheduledHostCallback ;
570
+ var prevTimeoutTime = timeoutTime ;
571
+ scheduledHostCallback = null ;
572
+ timeoutTime = - 1 ;
568
573
569
574
var currentTime = getCurrentTime ( ) ;
570
575
571
576
var didTimeout = false ;
572
577
if ( frameDeadline - currentTime <= 0 ) {
573
578
// There's no time left in this idle period. Check if the callback has
574
579
// a timeout and whether it's been exceeded.
575
- if ( timeoutTime !== - 1 && timeoutTime <= currentTime ) {
580
+ if ( prevTimeoutTime !== - 1 && prevTimeoutTime <= currentTime ) {
576
581
// Exceeded the timeout. Invoke the callback even though there's no
577
582
// time left.
578
583
didTimeout = true ;
@@ -584,19 +589,18 @@ if (typeof window !== 'undefined' && window._schedMock) {
584
589
requestAnimationFrameWithTimeout ( animationTick ) ;
585
590
}
586
591
// Exit without invoking the callback.
592
+ scheduledHostCallback = prevScheduledCallback ;
593
+ timeoutTime = prevTimeoutTime ;
587
594
return ;
588
595
}
589
596
}
590
597
591
- timeoutTime = - 1 ;
592
- var callback = scheduledCallback ;
593
- scheduledCallback = null ;
594
- if ( callback !== null ) {
595
- isPerformingIdleWork = true ;
598
+ if ( prevScheduledCallback !== null ) {
599
+ isFlushingHostCallback = true ;
596
600
try {
597
- callback ( didTimeout ) ;
601
+ prevScheduledCallback ( didTimeout ) ;
598
602
} finally {
599
- isPerformingIdleWork = false ;
603
+ isFlushingHostCallback = false ;
600
604
}
601
605
}
602
606
} ;
@@ -605,7 +609,22 @@ if (typeof window !== 'undefined' && window._schedMock) {
605
609
window . addEventListener ( 'message' , idleTick , false ) ;
606
610
607
611
var animationTick = function ( rafTime ) {
608
- isAnimationFrameScheduled = false ;
612
+ if ( scheduledHostCallback !== null ) {
613
+ // Eagerly schedule the next animation callback at the beginning of the
614
+ // frame. If the scheduler queue is not empty at the end of the frame, it
615
+ // will continue flushing inside that callback. If the queue *is* empty,
616
+ // then it will exit immediately. Posting the callback at the start of the
617
+ // frame ensures it's fired within the earliest possible frame. If we
618
+ // waited until the end of the frame to post the callback, we risk the
619
+ // browser skipping a frame and not firing the callback until the frame
620
+ // after that.
621
+ requestAnimationFrameWithTimeout ( animationTick ) ;
622
+ } else {
623
+ // No pending work. Exit.
624
+ isAnimationFrameScheduled = false ;
625
+ return ;
626
+ }
627
+
609
628
var nextFrameTime = rafTime - frameDeadline + activeFrameTime ;
610
629
if (
611
630
nextFrameTime < activeFrameTime &&
@@ -629,16 +648,16 @@ if (typeof window !== 'undefined' && window._schedMock) {
629
648
previousFrameTime = nextFrameTime ;
630
649
}
631
650
frameDeadline = rafTime + activeFrameTime ;
632
- if ( ! isIdleScheduled ) {
633
- isIdleScheduled = true ;
651
+ if ( ! isMessageEventScheduled ) {
652
+ isMessageEventScheduled = true ;
634
653
window . postMessage ( messageKey , '*' ) ;
635
654
}
636
655
} ;
637
656
638
657
requestHostCallback = function ( callback , absoluteTimeout ) {
639
- scheduledCallback = callback ;
658
+ scheduledHostCallback = callback ;
640
659
timeoutTime = absoluteTimeout ;
641
- if ( isPerformingIdleWork || absoluteTimeout < 0 ) {
660
+ if ( isFlushingHostCallback || absoluteTimeout < 0 ) {
642
661
// Don't wait for the next frame. Continue working ASAP, in a new event.
643
662
window . postMessage ( messageKey , '*' ) ;
644
663
} else if ( ! isAnimationFrameScheduled ) {
@@ -652,8 +671,8 @@ if (typeof window !== 'undefined' && window._schedMock) {
652
671
} ;
653
672
654
673
cancelHostCallback = function ( ) {
655
- scheduledCallback = null ;
656
- isIdleScheduled = false ;
674
+ scheduledHostCallback = null ;
675
+ isMessageEventScheduled = false ;
657
676
timeoutTime = - 1 ;
658
677
} ;
659
678
}
0 commit comments