@@ -2,21 +2,18 @@ import RenderQueue from "./RenderQueue.js";
2
2
import { getAllRegisteredTags } from "./CustomElementsRegistry.js" ;
3
3
import { isRtlAware } from "./locale/RTLAwareRegistry.js" ;
4
4
5
- const MAX_RERENDER_COUNT = 10 ;
6
5
const registeredElements = new Set ( ) ;
7
6
8
- // Tells whether a render task is currently scheduled
9
- let renderTaskId ;
10
-
11
7
// Queue for invalidated web components
12
8
const invalidatedWebComponents = new RenderQueue ( ) ;
13
9
14
10
let renderTaskPromise ,
15
- renderTaskPromiseResolve ,
16
- taskResult ;
11
+ renderTaskPromiseResolve ;
17
12
18
13
let mutationObserverTimer ;
19
14
15
+ let queuePromise ;
16
+
20
17
/**
21
18
* Class that manages the rendering/re-rendering of web components
22
19
* This is always asynchronous
@@ -27,77 +24,65 @@ class RenderScheduler {
27
24
}
28
25
29
26
/**
30
- * Queues a web component for re-rendering
27
+ * Schedules a render task (if not already scheduled) to render the component
28
+ *
31
29
* @param webComponent
30
+ * @returns {Promise }
32
31
*/
33
- static renderDeferred ( webComponent ) {
32
+ static async renderDeferred ( webComponent ) {
34
33
// Enqueue the web component
35
- const res = invalidatedWebComponents . add ( webComponent ) ;
34
+ invalidatedWebComponents . add ( webComponent ) ;
36
35
37
36
// Schedule a rendering task
38
- RenderScheduler . scheduleRenderTask ( ) ;
39
- return res ;
37
+ await RenderScheduler . scheduleRenderTask ( ) ;
40
38
}
41
39
40
+ /**
41
+ * Renders a component synchronously
42
+ *
43
+ * @param webComponent
44
+ */
42
45
static renderImmediately ( webComponent ) {
43
- // Enqueue the web component
44
- const res = invalidatedWebComponents . add ( webComponent ) ;
45
-
46
- // Immediately start a render task
47
- RenderScheduler . runRenderTask ( ) ;
48
- return res ;
46
+ webComponent . _render ( ) ;
49
47
}
50
48
51
49
/**
52
- * Schedules a rendering task, if not scheduled already
50
+ * Cancels the rendering of a component, added to the queue with renderDeferred
51
+ *
52
+ * @param webComponent
53
53
*/
54
- static scheduleRenderTask ( ) {
55
- if ( ! renderTaskId ) {
56
- // renderTaskId = window.setTimeout(RenderScheduler.renderWebComponents, 3000); // Task
57
- // renderTaskId = Promise.resolve().then(RenderScheduler.renderWebComponents); // Micro task
58
- renderTaskId = window . requestAnimationFrame ( RenderScheduler . renderWebComponents ) ; // AF
59
- }
60
- }
61
-
62
- static runRenderTask ( ) {
63
- if ( ! renderTaskId ) {
64
- renderTaskId = 1 ; // prevent another rendering task from being scheduled, all web components should use this task
65
- RenderScheduler . renderWebComponents ( ) ;
66
- }
54
+ static cancelRender ( webComponent ) {
55
+ invalidatedWebComponents . remove ( webComponent ) ;
67
56
}
68
57
69
- static renderWebComponents ( ) {
70
- // console.log("------------- NEW RENDER TASK ---------------");
71
-
72
- let webComponentInfo ,
73
- webComponent ,
74
- promise ;
75
- const renderStats = new Map ( ) ;
76
- while ( webComponentInfo = invalidatedWebComponents . shift ( ) ) { // eslint-disable-line
77
- webComponent = webComponentInfo . webComponent ;
78
- promise = webComponentInfo . promise ;
79
-
80
- const timesRerendered = renderStats . get ( webComponent ) || 0 ;
81
- if ( timesRerendered > MAX_RERENDER_COUNT ) {
82
- // console.warn("WARNING RERENDER", webComponent);
83
- throw new Error ( `Web component re-rendered too many times this task, max allowed is: ${ MAX_RERENDER_COUNT } ` ) ;
84
- }
85
- webComponent . _render ( ) ;
86
- promise . _deferredResolve ( ) ;
87
- renderStats . set ( webComponent , timesRerendered + 1 ) ;
88
- }
58
+ /**
59
+ * Schedules a rendering task, if not scheduled already
60
+ */
61
+ static async scheduleRenderTask ( ) {
62
+ if ( ! queuePromise ) {
63
+ queuePromise = new Promise ( resolve => {
64
+ window . requestAnimationFrame ( ( ) => {
65
+ // Render all components in the queue
66
+ invalidatedWebComponents . process ( component => component . _render ( ) ) ;
67
+
68
+ // Resolve the promise so that callers of renderDeferred can continue
69
+ queuePromise = null ;
70
+ resolve ( ) ;
89
71
90
- // wait for Mutation observer just in case
91
- if ( ! mutationObserverTimer ) {
92
- mutationObserverTimer = setTimeout ( ( ) => {
93
- mutationObserverTimer = undefined ;
94
- if ( invalidatedWebComponents . getList ( ) . length === 0 ) {
95
- RenderScheduler . _resolveTaskPromise ( ) ;
96
- }
97
- } , 200 ) ;
72
+ // Wait for Mutation observer before the render task is considered finished
73
+ if ( ! mutationObserverTimer ) {
74
+ mutationObserverTimer = setTimeout ( ( ) => {
75
+ mutationObserverTimer = undefined ;
76
+ if ( invalidatedWebComponents . isEmpty ( ) ) {
77
+ RenderScheduler . _resolveTaskPromise ( ) ;
78
+ }
79
+ } , 200 ) ;
80
+ }
81
+ } ) ;
82
+ } ) ;
98
83
}
99
84
100
- renderTaskId = undefined ;
85
+ await queuePromise ;
101
86
}
102
87
103
88
/**
@@ -111,7 +96,7 @@ class RenderScheduler {
111
96
renderTaskPromise = new Promise ( resolve => {
112
97
renderTaskPromiseResolve = resolve ;
113
98
window . requestAnimationFrame ( ( ) => {
114
- if ( invalidatedWebComponents . getList ( ) . length === 0 ) {
99
+ if ( invalidatedWebComponents . isEmpty ( ) ) {
115
100
renderTaskPromise = undefined ;
116
101
resolve ( ) ;
117
102
}
@@ -132,13 +117,13 @@ class RenderScheduler {
132
117
}
133
118
134
119
static _resolveTaskPromise ( ) {
135
- if ( invalidatedWebComponents . getList ( ) . length > 0 ) {
120
+ if ( ! invalidatedWebComponents . isEmpty ( ) ) {
136
121
// More updates are pending. Resolve will be called again
137
122
return ;
138
123
}
139
124
140
125
if ( renderTaskPromiseResolve ) {
141
- renderTaskPromiseResolve . call ( this , taskResult ) ;
126
+ renderTaskPromiseResolve . call ( this ) ;
142
127
renderTaskPromiseResolve = undefined ;
143
128
renderTaskPromise = undefined ;
144
129
}
0 commit comments