Skip to content

Commit 6076c02

Browse files
committed
[LiveComponent] Avoid polling over renders
1 parent fcf9444 commit 6076c02

File tree

2 files changed

+28
-11
lines changed

2 files changed

+28
-11
lines changed

src/LiveComponent/assets/dist/live_controller.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,7 @@ class default_1 extends Controller {
11071107
});
11081108
}
11091109
$render() {
1110-
this._makeRequest(null);
1110+
this._makeRequest(null, {});
11111111
}
11121112
_getValueFromElement(element) {
11131113
return element.dataset.value || element.value;
@@ -1121,17 +1121,18 @@ class default_1 extends Controller {
11211121
const clonedElement = cloneHTMLElement(element);
11221122
throw new Error(`The update() method could not be called for "${clonedElement.outerHTML}": the element must either have a "data-model" or "name" attribute set to the model name.`);
11231123
}
1124+
let finalValue = value;
11241125
if (/\[]$/.test(model)) {
11251126
const { currentLevelData, finalKey } = parseDeepData(this.dataValue, normalizeModelName(model));
11261127
const currentValue = currentLevelData[finalKey];
1127-
value = updateArrayDataFromChangedElement(element, value, currentValue);
1128+
finalValue = updateArrayDataFromChangedElement(element, value, currentValue);
11281129
}
11291130
else if (element instanceof HTMLInputElement
11301131
&& element.type === 'checkbox'
11311132
&& !element.checked) {
1132-
value = null;
1133+
finalValue = null;
11331134
}
1134-
this.$updateModel(model, value, shouldRender, element.hasAttribute('name') ? element.getAttribute('name') : null, {});
1135+
this.$updateModel(model, finalValue, shouldRender, element.hasAttribute('name') ? element.getAttribute('name') : null, {});
11351136
}
11361137
$updateModel(model, value, shouldRender = true, extraModelName = null, options = {}) {
11371138
const directives = parseDirectives(model);
@@ -1427,10 +1428,13 @@ class default_1 extends Controller {
14271428
}
14281429
else {
14291430
callback = () => {
1430-
this._makeRequest(actionName);
1431+
this._makeRequest(actionName, {});
14311432
};
14321433
}
14331434
const timer = setInterval(() => {
1435+
if (this.renderPromiseStack.countActivePromises() > 0) {
1436+
return;
1437+
}
14341438
callback();
14351439
}, duration);
14361440
this.pollingIntervals.push(timer);
@@ -1539,6 +1543,9 @@ class PromiseStack {
15391543
findPromiseIndex(promise) {
15401544
return this.stack.findIndex((item) => item === promise);
15411545
}
1546+
countActivePromises() {
1547+
return this.stack.length;
1548+
}
15421549
}
15431550
const parseLoadingAction = function (action, isLoading) {
15441551
switch (action) {

src/LiveComponent/assets/src/live_controller.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ export default class extends Controller {
184184
}
185185

186186
$render() {
187-
this._makeRequest(null);
187+
this._makeRequest(null, {});
188188
}
189189

190190
_getValueFromElement(element: HTMLElement|SVGElement) {
@@ -206,22 +206,23 @@ export default class extends Controller {
206206
// HTML form elements with name ending with [] require array as data
207207
// we need to handle addition and removal of values from it to send
208208
// back only required data
209+
let finalValue : string|null|string[] = value
209210
if (/\[]$/.test(model)) {
210211
// Get current value from data
211212
const { currentLevelData, finalKey } = parseDeepData(this.dataValue, normalizeModelName(model))
212213
const currentValue = currentLevelData[finalKey];
213214

214-
value = updateArrayDataFromChangedElement(element, value, currentValue);
215+
finalValue = updateArrayDataFromChangedElement(element, value, currentValue);
215216
} else if (
216217
element instanceof HTMLInputElement
217218
&& element.type === 'checkbox'
218219
&& !element.checked
219220
) {
220221
// Unchecked checkboxes in a single value scenarios should map to `null`
221-
value = null;
222+
finalValue = null;
222223
}
223224

224-
this.$updateModel(model, value, shouldRender, element.hasAttribute('name') ? element.getAttribute('name') : null, {});
225+
this.$updateModel(model, finalValue, shouldRender, element.hasAttribute('name') ? element.getAttribute('name') : null, {});
225226
}
226227

227228
/**
@@ -309,7 +310,7 @@ export default class extends Controller {
309310
}
310311
}
311312

312-
_makeRequest(action: string|null, args: Record<string,unknown>) {
313+
_makeRequest(action: string|null, args: Record<string, string>) {
313314
const splitUrl = this.urlValue.split('?');
314315
let [url] = splitUrl
315316
const [, queryString] = splitUrl;
@@ -659,11 +660,16 @@ export default class extends Controller {
659660
}
660661
} else {
661662
callback = () => {
662-
this._makeRequest(actionName);
663+
this._makeRequest(actionName, {});
663664
}
664665
}
665666

666667
const timer = setInterval(() => {
668+
// if there is already an active render promise, skip the poll
669+
if (this.renderPromiseStack.countActivePromises() > 0) {
670+
return;
671+
}
672+
667673
callback();
668674
}, duration);
669675
this.pollingIntervals.push(timer);
@@ -820,6 +826,10 @@ class PromiseStack {
820826
findPromiseIndex(promise: Promise<any>) {
821827
return this.stack.findIndex((item) => item === promise);
822828
}
829+
830+
countActivePromises(): number {
831+
return this.stack.length;
832+
}
823833
}
824834

825835
const parseLoadingAction = function(action: string, isLoading: boolean) {

0 commit comments

Comments
 (0)