From ff72522f30028952ffc531f7af7ddb280842a037 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 26 Nov 2021 16:11:40 +0000 Subject: [PATCH] PERF: Use passive event listeners for touchstart, touchmove None of these places call `event.preventDefault()`. Therefore we can register the event listeners as 'passive', and improve scroll performance on mobile devices. --- .../discourse/app/components/composer-editor.js | 8 ++++++-- .../app/components/scrolling-post-stream.js | 15 +++++++++------ .../javascripts/discourse/app/lib/lock-on.js | 2 +- .../javascripts/discourse/app/mixins/docking.js | 6 ++++-- .../discourse/app/mixins/pan-events.js | 11 +++++++---- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/app/assets/javascripts/discourse/app/components/composer-editor.js b/app/assets/javascripts/discourse/app/components/composer-editor.js index a32f47eaf92..a5287c8eef4 100644 --- a/app/assets/javascripts/discourse/app/components/composer-editor.js +++ b/app/assets/javascripts/discourse/app/components/composer-editor.js @@ -360,10 +360,14 @@ export default Component.extend(ComposerUpload, { }); schedule("afterRender", () => { - input?.addEventListener("touchstart", this._handleInputInteraction); + input?.addEventListener("touchstart", this._handleInputInteraction, { + passive: true, + }); input?.addEventListener("mouseenter", this._handleInputInteraction); - preview?.addEventListener("touchstart", this._handlePreviewInteraction); + preview?.addEventListener("touchstart", this._handlePreviewInteraction, { + passive: true, + }); preview?.addEventListener("mouseenter", this._handlePreviewInteraction); }); }, diff --git a/app/assets/javascripts/discourse/app/components/scrolling-post-stream.js b/app/assets/javascripts/discourse/app/components/scrolling-post-stream.js index 8234c21b363..c634f0336eb 100644 --- a/app/assets/javascripts/discourse/app/components/scrolling-post-stream.js +++ b/app/assets/javascripts/discourse/app/components/scrolling-post-stream.js @@ -6,6 +6,7 @@ import discourseDebounce from "discourse-common/lib/debounce"; import { isWorkaroundActive } from "discourse/lib/safari-hacks"; import offsetCalculator from "discourse/lib/offset-calculator"; import { inject as service } from "@ember/service"; +import { bind } from "discourse-common/utils/decorators"; const DEBOUNCE_DELAY = 50; @@ -320,19 +321,21 @@ export default MountWidget.extend({ this.queueRerender(); }, + @bind _debouncedScroll() { discourseDebounce(this, this._scrollTriggered, DEBOUNCE_DELAY); }, didInsertElement() { this._super(...arguments); - const debouncedScroll = () => - discourseDebounce(this, this._scrollTriggered, DEBOUNCE_DELAY); this._previouslyNearby = {}; this.appEvents.on("post-stream:refresh", this, "_debouncedScroll"); - $(document).bind("touchmove.post-stream", debouncedScroll); - $(window).bind("scroll.post-stream", debouncedScroll); + const opts = { + passive: true, + }; + document.addEventListener("touchmove", this._debouncedScroll, opts); + window.addEventListener("scroll", this._debouncedScroll, opts); this._scrollTriggered(); this.appEvents.on("post-stream:posted", this, "_posted"); @@ -362,8 +365,8 @@ export default MountWidget.extend({ willDestroyElement() { this._super(...arguments); - $(document).unbind("touchmove.post-stream"); - $(window).unbind("scroll.post-stream"); + document.removeEventListener("touchmove", this._debouncedScrollCallback); + window.removeEventListener("scroll", this._debouncedScrollCallback); this.appEvents.off("post-stream:refresh", this, "_debouncedScroll"); $(this.element).off("mouseenter.post-stream"); $(this.element).off("mouseleave.post-stream"); diff --git a/app/assets/javascripts/discourse/app/lib/lock-on.js b/app/assets/javascripts/discourse/app/lib/lock-on.js index b8a86ae2f6f..32a92b342bd 100644 --- a/app/assets/javascripts/discourse/app/lib/lock-on.js +++ b/app/assets/javascripts/discourse/app/lib/lock-on.js @@ -87,7 +87,7 @@ export default class LockOn { const body = document.querySelector("body"); SCROLL_EVENTS.forEach((event) => { - body.addEventListener(event, this._scrollListener); + body.addEventListener(event, this._scrollListener, { passive: true }); }); } diff --git a/app/assets/javascripts/discourse/app/mixins/docking.js b/app/assets/javascripts/discourse/app/mixins/docking.js index e8de346cbc8..e97638ae5a6 100644 --- a/app/assets/javascripts/discourse/app/mixins/docking.js +++ b/app/assets/javascripts/discourse/app/mixins/docking.js @@ -32,8 +32,10 @@ export default Mixin.create({ didInsertElement() { this._super(...arguments); - window.addEventListener("scroll", this.queueDockCheck); - document.addEventListener("touchmove", this.queueDockCheck); + window.addEventListener("scroll", this.queueDockCheck, { passive: true }); + document.addEventListener("touchmove", this.queueDockCheck, { + passive: true, + }); // dockCheck might happen too early on full page refresh this._initialTimer = later(this, this.safeDockCheck, 50); diff --git a/app/assets/javascripts/discourse/app/mixins/pan-events.js b/app/assets/javascripts/discourse/app/mixins/pan-events.js index 01346472676..63db26161a5 100644 --- a/app/assets/javascripts/discourse/app/mixins/pan-events.js +++ b/app/assets/javascripts/discourse/app/mixins/pan-events.js @@ -33,10 +33,13 @@ export default Mixin.create({ this.touchEnd = (e) => this._panMove({ type: "pointerup" }, e); this.touchCancel = (e) => this._panMove({ type: "pointercancel" }, e); - element.addEventListener("touchstart", this.touchStart); - element.addEventListener("touchmove", this.touchMove); - element.addEventListener("touchend", this.touchEnd); - element.addEventListener("touchcancel", this.touchCancel); + const opts = { + passive: true, + }; + element.addEventListener("touchstart", this.touchStart, opts); + element.addEventListener("touchmove", this.touchMove, opts); + element.addEventListener("touchend", this.touchEnd, opts); + element.addEventListener("touchcancel", this.touchCancel, opts); } },