From f20db92512a0c692773397855af582ff7065a396 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 29 Nov 2024 16:32:59 +0000 Subject: [PATCH] UX: Improve loading-slider behavior (#29995) - Use `requestAnimationFrame` when transitioning from `ready` -> `loading`. The previous `next()` implementation was unreliable, particularly in Safari, and would cause the loading slider to jump backwards instead of forwards - Double the minimum transition time to 200ms. This avoids the rolling average being skewed too much by routes which load quickly without network access. --- .../discourse/app/components/page-loading-slider.gjs | 12 +++++++++--- .../discourse/app/services/loading-slider.js | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/discourse/app/components/page-loading-slider.gjs b/app/assets/javascripts/discourse/app/components/page-loading-slider.gjs index 1fb2ac66a0b..27244e2189e 100644 --- a/app/assets/javascripts/discourse/app/components/page-loading-slider.gjs +++ b/app/assets/javascripts/discourse/app/components/page-loading-slider.gjs @@ -2,7 +2,7 @@ import Component from "@glimmer/component"; import { tracked } from "@glimmer/tracking"; import { on } from "@ember/modifier"; import { action } from "@ember/object"; -import { cancel, next } from "@ember/runloop"; +import { run } from "@ember/runloop"; import { service } from "@ember/service"; import { htmlSafe } from "@ember/template"; import { eq } from "truth-helpers"; @@ -23,12 +23,16 @@ export default class PageLoadingSlider extends Component { willDestroy() { super.willDestroy(...arguments); this.loadingSlider.off("stateChange", this, "stateChange"); + if (this._deferredStateChange) { + cancelAnimationFrame(this._deferredStateChange); + this._deferredStateChange = null; + } } @bind stateChanged(loading) { if (this._deferredStateChange) { - cancel(this._deferredStateChange); + cancelAnimationFrame(this._deferredStateChange); this._deferredStateChange = null; } @@ -36,7 +40,9 @@ export default class PageLoadingSlider extends Component { this.state = "loading"; } else if (loading) { this.state = "ready"; - this._deferredStateChange = next(() => (this.state = "loading")); + this._deferredStateChange = requestAnimationFrame(() => { + run(() => (this.state = "loading")); + }); } else { this.state = "done"; } diff --git a/app/assets/javascripts/discourse/app/services/loading-slider.js b/app/assets/javascripts/discourse/app/services/loading-slider.js index afdfa3f0d26..be9555456c6 100644 --- a/app/assets/javascripts/discourse/app/services/loading-slider.js +++ b/app/assets/javascripts/discourse/app/services/loading-slider.js @@ -7,7 +7,7 @@ import { bind } from "discourse-common/utils/decorators"; const STORE_LOADING_TIMES = 5; const DEFAULT_LOADING_TIME = 0.3; -const MIN_LOADING_TIME = 0.1; +const MIN_LOADING_TIME = 0.2; const STILL_LOADING_DURATION = 2;