@@ -76,6 +76,15 @@ const PagesCountLimit = {
76
76
PAUSE_EAGER_PAGE_INIT : 250 ,
77
77
} ;
78
78
79
+ // These constants need to be chosen such that the maximum delay, before
80
+ // rendering is triggered, cannot exceed the `DELAYED_CLEANUP_TIMEOUT` value
81
+ // defined in the `src/display/api.js` file.
82
+ const RenderHighestPriorityDelay = {
83
+ CALLS : 15 , // num
84
+ TIMEOUT : 20 , // ms
85
+ TIME_DELTA : 20 , // ms
86
+ } ;
87
+
79
88
function isValidAnnotationEditorMode ( mode ) {
80
89
return (
81
90
Object . values ( AnnotationEditorType ) . includes ( mode ) &&
@@ -228,6 +237,8 @@ class PDFViewer {
228
237
229
238
#resizeObserver = new ResizeObserver ( this . #resizeObserverCallback. bind ( this ) ) ;
230
239
240
+ #rhp = null ;
241
+
231
242
#scrollModePageState = null ;
232
243
233
244
#onVisibilityChange = null ;
@@ -1073,6 +1084,15 @@ class PDFViewer {
1073
1084
this . _previousScrollMode = ScrollMode . UNKNOWN ;
1074
1085
this . _spreadMode = SpreadMode . NONE ;
1075
1086
1087
+ if ( this . #rhp?. timeout ) {
1088
+ clearTimeout ( this . #rhp. timeout ) ;
1089
+ }
1090
+ this . #rhp = {
1091
+ calls : 0 ,
1092
+ timeout : null ,
1093
+ timeStamp : performance . now ( ) ,
1094
+ } ;
1095
+
1076
1096
this . #scrollModePageState = {
1077
1097
previousPageNumber : 1 ,
1078
1098
scrollDown : true ,
@@ -1177,7 +1197,7 @@ class PDFViewer {
1177
1197
if ( this . pagesCount === 0 ) {
1178
1198
return ;
1179
1199
}
1180
- this . update ( ) ;
1200
+ this . update ( /* scrolled = */ true ) ;
1181
1201
}
1182
1202
1183
1203
#scrollIntoView( pageView , pageSpot = null ) {
@@ -1594,7 +1614,7 @@ class PDFViewer {
1594
1614
} ;
1595
1615
}
1596
1616
1597
- update ( ) {
1617
+ update ( scrolled = false ) {
1598
1618
const visible = this . _getVisiblePages ( ) ;
1599
1619
const visiblePages = visible . views ,
1600
1620
numVisiblePages = visiblePages . length ;
@@ -1605,7 +1625,48 @@ class PDFViewer {
1605
1625
const newCacheSize = Math . max ( DEFAULT_CACHE_SIZE , 2 * numVisiblePages + 1 ) ;
1606
1626
this . #buffer. resize ( newCacheSize , visible . ids ) ;
1607
1627
1608
- this . renderingQueue . renderHighestPriority ( visible ) ;
1628
+ const rhp = this . #rhp;
1629
+ rhp . calls ++ ;
1630
+ if ( rhp . timeout ) {
1631
+ clearTimeout ( rhp . timeout ) ;
1632
+ rhp . timeout = null ;
1633
+ }
1634
+ const timeStamp = performance . now ( ) ,
1635
+ timeDelta = timeStamp - rhp . timeStamp ;
1636
+ rhp . timeStamp = timeStamp ;
1637
+
1638
+ // To improve overall performance, when scrolling very quickly through long
1639
+ // and complex PDF documents, we try to *slightly* delay rendering here.
1640
+ // For PDF documents that contain e.g. large images this should also help
1641
+ // reduce overall memory usage during parsing.
1642
+ //
1643
+ // Note that while main-thread rendering will be cancelled quickly, any
1644
+ // ongoing worker-thread parsing will be aborted with a small delay.
1645
+ // Hence it's possible to "overburden" the worker-thread with pages that
1646
+ // are almost immediately evicted from the `PDFPageViewBuffer` cache,
1647
+ // if rendering is triggered on every single scroll-event.
1648
+ //
1649
+ // To avoid the viewer feeling more "sluggish" than before, for short and
1650
+ // simple PDF documents, we need to ensure that rendering won't be delayed
1651
+ // "indefinitely" hence the following heuristics are used to trigger
1652
+ // rendering immediately:
1653
+ // - If the `update`-method was *not* called from a scroll-event.
1654
+ // - For every nth time that the `update`-method is called.
1655
+ // - At least once for every nth milliseconds.
1656
+ if (
1657
+ ! scrolled ||
1658
+ rhp . calls > RenderHighestPriorityDelay . CALLS ||
1659
+ timeDelta > RenderHighestPriorityDelay . TIME_DELTA
1660
+ ) {
1661
+ rhp . calls = 0 ;
1662
+ this . renderingQueue . renderHighestPriority ( visible ) ;
1663
+ } else {
1664
+ rhp . timeout = setTimeout ( ( ) => {
1665
+ rhp . calls = 0 ;
1666
+ rhp . timeout = null ;
1667
+ this . renderingQueue . renderHighestPriority ( visible ) ;
1668
+ } , RenderHighestPriorityDelay . TIMEOUT ) ;
1669
+ }
1609
1670
1610
1671
const isSimpleLayout =
1611
1672
this . _spreadMode === SpreadMode . NONE &&
0 commit comments