Fixed layout thrashing when `Stream Fade-In` and `Auto-scroll Chat` are enabled. (#4791) * Scheduling scrollChatToBottom after the animation frame prevents layout thrashing. https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#return_value https://gist.github.com/paulirish/5d52fb081b3570c81e3a#file-what-forces-layout-md * Make frame request optional --------- Co-authored-by: user <user@exmaple.com> Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

ffe17bb870ee56e6323e852505e76ddce38069ba

DeclineThyself <235079501+DeclineThyself@users.noreply.github.com>

Signed
1 files changed, +32 -5Ignore whitespace
public/script.js+32 -5
@@ -1451,7 +1451,7 @@ function scrollOnMediaLoad() {
14511451 }
14521452 mediaLoaded++;
14531453 if (mediaLoaded === media.length) {
14541454 scrollChatToBottom({ waitForFrame: true });
14551455 }
14561456 }
14571457}
@@ -2598,8 +2598,19 @@ function formatGenerationTimer(gen_started, gen_finished, tokenCount, reasoningD
25982598 return { timerValue, timerTitle };
25992599}
26002600
2601-export function scrollChatToBottom() {
2601+let requestId = null;
2602- if (power_user.auto_scroll_chat_to_bottom) {
2602+
2603+/**
2604+ * Scrolls the chat to the bottom if configured to do so.
2605+ * @param {object} [options] Options
2606+ * @param {boolean} [options.waitForFrame] If true, waits for the animation frame before scrolling
2607+ */
2608+export function scrollChatToBottom({ waitForFrame } = {}) {
2609+ if (!power_user.auto_scroll_chat_to_bottom) {
2610+ return;
2611+ }
2612+
2613+ const doScroll = () => {
26032614 let position = chatElement[0].scrollHeight;
26042615
26052616 if (power_user.waifuMode) {
@@ -2611,7 +2622,23 @@ export function scrollChatToBottom() {
26112622 }
26122623
26132624 chatElement.scrollTop(position);
2625+ requestId = null;
2626+ };
2627+
2628+ // Do not check truthiness. requestId can loop to zero.
2629+ if (requestId !== null) {
2630+ cancelAnimationFrame(requestId);
26142631 }
2632+
2633+ if (!waitForFrame) {
2634+ doScroll();
2635+ return;
2636+ }
2637+
2638+ // This prevents layout thrashing.
2639+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#return_value
2640+ // https://gist.github.com/paulirish/5d52fb081b3570c81e3a#file-what-forces-layout-md
2641+ requestId = requestAnimationFrame(() => doScroll());
26152642}
26162643
26172644/**
@@ -3273,7 +3300,7 @@ class StreamingProcessor {
32733300 this.markUIGenStarted();
32743301 }
32753302 hideSwipeButtons({ hideCounters: true });
32763303 scrollChatToBottom({ waitForFrame: true });
32773304 return messageId;
32783305 }
32793306
@@ -3376,7 +3403,7 @@ class StreamingProcessor {
33763403 }
33773404
33783405 if (!scrollLock) {
33793406 scrollChatToBottom({ waitForFrame: true });
33803407 }
33813408 }
33823409