Defer intersection monitoring until needed to prevent race conditions (#7278)

* defer visibility rendering until actually used to prevent race conditions

* remove extrace space
This commit is contained in:
Scott Bell 2023-12-15 09:40:36 +01:00 committed by GitHub
parent 4075a31d96
commit 2675220452
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 14 additions and 3 deletions

2
API.md
View File

@ -1319,6 +1319,8 @@ The `renderWhenVisible` function is passed to the show function as part of the `
Additionally, `renderWhenVisible` returns a boolean value indicating whether the provided function was executed immediately (`true`) or deferred (`false`).
Monitoring of visibility begins after the first call to `renderWhenVisible` is made.
Heres the signature for the show function:
`show(element, isEditing, viewOptions)`

View File

@ -199,8 +199,8 @@ export default {
mounted() {
this.chartVisible = true;
this.chartContainer = this.$refs.chart;
this.drawnOnce = false;
this.visibilityObserver = new IntersectionObserver(this.visibilityChanged);
this.visibilityObserver.observe(this.chartContainer);
eventHelpers.extend(this);
this.seriesModels = [];
this.config = this.getConfig();
@ -687,6 +687,10 @@ export default {
if (!this.drawScheduled) {
const called = this.renderWhenVisible(this.draw);
this.drawScheduled = called;
if (!this.drawnOnce && called) {
this.drawnOnce = true;
this.visibilityObserver.observe(this.chartContainer);
}
}
},
draw() {

View File

@ -40,9 +40,9 @@ export default class VisibilityObserver {
}
this.#element = element;
this.isIntersecting = true;
this.calledOnce = false;
this.#observer = new IntersectionObserver(this.#observerCallback);
this.#observer.observe(this.#element);
this.lastUnfiredFunc = null;
this.renderWhenVisible = this.renderWhenVisible.bind(this);
}
@ -66,7 +66,12 @@ export default class VisibilityObserver {
* @returns {boolean} True if the function was executed immediately, false otherwise.
*/
renderWhenVisible(func) {
if (this.isIntersecting) {
if (!this.calledOnce) {
this.calledOnce = true;
this.#observer.observe(this.#element);
window.requestAnimationFrame(func);
return true;
} else if (this.isIntersecting) {
window.requestAnimationFrame(func);
return true;
} else {