Gunnar Bittersmann: Ich throttle

Ich habe ein Menü, das einzeilig bleibt und horizontal gescrollt wird. Dabei wird die Scrollbar ausgeblendet; dafür gibt’s Buttons für Zurückscrollen und Vorscrollen. Diese werden per JavaScript ansgeblendet, wenn man sich am Anfang bzw. Ende befindet.

Beim Scrollen feuert das scroll-Event ständig. (Irgendwo gelesen, dass es auf Smartphones noch häufiger feuert als auf „Großrechnern“.) Die Eventhandlerfunktion sollte daher in ihrer Ausführung beschränkt werden.

Besser als nichts: mit requestAnimationFrame. Damit ist die Ausführung aber immer noch häufiger als nötig. Man sollte Debouncing oder Throttling implementieren.[1][2][3][4]

Mit Debouncing funktioniert’s, liefert aber nicht das gewünschte Ergebnis: Das Ein-/Ausblenden eines Pfeils erfolgt erst eine gewisse Zeit, nachdem man mit Scrollen aufgehört hat, nicht schon währenddessen.

Das sollte also mit Throttling gemacht werden. Funktioniert aber nicht. Kann mir jemand sagen, warum nicht?

🖖 Живіть довго і процвітайте

--
„Im Vergleich mit Elon Musk bei Twitter ist ein Elefant im Porzellanladen eine Ballerina.“
— @Grantscheam auf Twitter

  1. The Difference Between Throttling and Debouncing by Chris Coyier ↩︎

  2. Debouncing and Throttling Explained Through Examples by David Corbacho ↩︎

  3. Optimizing window.onresize by Ben Centra ↩︎

  4. Debounce vs Throttle: Definitive Visual Guide by Artem Zakharchenko ↩︎

  1. Hallo Gunnar Bittersmann,

    ich bin mir nicht sicher, ob ich das gleiche "funktioniert nicht" erlebe wie Du. Ich sehe nämlich im "throttle" Beispiel gar keine Pfeilchen. Wenn ich aber dorthin klicke, wo sie sein sollten, scrollt das Menü.

    Wenn ich mit der Tab-Taste durchlaufe und focusin zuschlägt, erfolgt das Scrollen nicht immer smooth. Nur bei kleinen Scrollmengen. Beim Sprung von Prodigy nach SNW dagegen gibt's einen Sprung.

    Edit 1: Ok, das Scrollen beim "dahin klicken wo der Pfeil ist" dürfte am focusin liegen - ich klicke eine Haaresbreite eines Titels an und der wird vom focusin-Handler ins Blickfeld gerollt.

    Edit 2: Deine toogleScrollButtonsThrottled-Funktion ruft throttle(fn, time) auf. Allerdings tut throttle nichts, sondern liefert eine verthrottlete Funktion zurück, die Du dann an Stelle der unverthrottleten Funktion verwenden kannst. Es funktioniert also nicht, diese Funktion

    function toogleScrollButtonsThrottled() {
    	throttle(toogleScrollButtons, 200);
    }
    

    als Eventhandler zu setzen. Du müsstest sie im addEventListener als Funktion aufrufen, und Du müsstest das Ergebnis von throttle zurückgeben. Das ist aber unnötige Mühe, mach es so:

    const toogleScrollButtonsThrottled = throttle(toogleScrollButtons, 200);
    

    Jetzt gehen nur die Pfeile nicht mehr weg.

    Edit 2: Was vermutlich daran liegt, dass die Chance hoch ist, dass der letzte Aufruf von toggleScrollButtonsThrottled zu einem Throttling führt. Entweder baust Du in den setTimeout-Aufruf in throttle einen "Nachklapperer" ein, der die Funktion ein letztes Mal aufruft nachdem gethrottelt wurde, oder Du brauchst ein zweites Event, dass das Ende des Scrollings erkennt.

    Der Nachklapperer führt dann aber zum gleichen Verhalten wie das Debouncing - der Pfeil verschwindet erst nach einer Verzögerung. Du musst also vermutlich irgendwie anders erkennen, dass Du am Anschlag angekommen bist.

    Die Eventhandlerfunktion sollte daher in ihrer Ausführung beschränkt werden.

    Wieso eigentlich. Warum findest Du es so schlimm, dass das hidden-Flag zu oft zugewiesen wird? Solange sich das Flag seinen Wert nicht ändert, dürfte das im Browser keine Aktion hervorrufen. Ohne Throttle scheint der Pen ganz prima zu funktionieren.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Wo ist Cheatah eigentlich abgeblieben?

      1. Hallo Peter,

        jetzt hast Du auf einen Zitathinweis geantwortet, den ich wieder entfernt hatte. Verdammt - erwischt 😉

        Tja, Cheatah, den hätte ich gern kennengelernt. Er ist vor knapp 10 Jahren zuletzt in Erscheinung getreten und sein Userkonto ist mittlerweile archiviert.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hallo,

          Tja, Cheatah, den hätte ich gern kennengelernt.

          ich auch. Ich habe ihn immerhin in einigen Threads im Forum als Live-Kommunikationspartner erlebt; ich habe festgestellt, dass ich die eine oder andere Humor-Ader mit ihm gemeinsam habe, auch die eine oder andere sachlich-technische Überzeugung.

          Persönlich habe ich ihn aber auch nie getroffen. Schade.

          Einen schönen Tag noch
           Martin

          --
          Möchtegern-Dichter zum Verleger: "Sie meinen also, ich sollte etwas mehr Feuer in meine Verse legen?" - "Umgekehrt, mein Lieber, umgekehrt. Mehr Verse ins Feuer."
        2. @@Rolf B

          Tja, Cheatah, den hätte ich gern kennengelernt.

          Ich auch. Persönlich hab ich ihn leider nie getroffen. So wie ich ihn hier im Forum kennengelernt habe, reicht das aus, ihn schmerzlich zu vermissen.

          Er ist vor knapp 10 Jahren zuletzt in Erscheinung getreten

          … und nach einer über viele Wochen andauernden Downtime des Forums nicht wieder aufgetaucht. Schade.

          🖖 Живіть довго і процвітайте

          --
          „Im Vergleich mit Elon Musk bei Twitter ist ein Elefant im Porzellanladen eine Ballerina.“
          — @Grantscheam auf Twitter
          1. da gibt es ja so einige, die leider nicht mehr aufgetaucht sind. Warum gab es diese Downtime? Kann mich nicht mehr erinnern, bin aber seit Jahrzehnten fleißiger Mitleser.

            1. Hallo,

              da gibt es ja so einige, die leider nicht mehr aufgetaucht sind.

              ja, und ich bedaure das bei vielen.

              Warum gab es diese Downtime?

              Es gab einmal einen längeren Ausfall aus technischen Gründen. Und es gab mal eine Phase, wo das Forum mehrere Monate geschlossen war, weil die Umgangsformen sich so übel entwickelt haben, dass es immer wieder Reibereien gab.

              Welche dieser Schließungen wann war, kann ich aber auch nicht mehr sagen.

              Einen schönen Tag noch
               Martin

              --
              Möchtegern-Dichter zum Verleger: "Sie meinen also, ich sollte etwas mehr Feuer in meine Verse legen?" - "Umgekehrt, mein Lieber, umgekehrt. Mehr Verse ins Feuer."
              1. @@Der Martin

                Warum gab es diese Downtime?

                Es gab einmal einen längeren Ausfall aus technischen Gründen. Und es gab mal eine Phase, wo das Forum mehrere Monate geschlossen war, weil die Umgangsformen sich so übel entwickelt haben, dass es immer wieder Reibereien gab.

                Welche dieser Schließungen wann war, kann ich aber auch nicht mehr sagen.

                AFAIR war dieser längere Ausfall aus technischen Gründen.

                🖖 Живіть довго і процвітайте

                --
                „Im Vergleich mit Elon Musk bei Twitter ist ein Elefant im Porzellanladen eine Ballerina.“
                — @Grantscheam auf Twitter
                1. Servus!

                  Warum gab es diese Downtime?

                  Welche dieser Schließungen wann war, kann ich aber auch nicht mehr sagen.

                  2012

                  AFAIR war dieser längere Ausfall aus technischen Gründen.

                  SELFHTML:Verein/Chronik#Krise_und_Katharsis

                  Ein Server war abgeraucht. Das hätte man durch einen Mietserver wieder hinkriegen können.

                  Allerdings zeigte sich, dass die Software aus so vielen Schichten in allen möglichen Programmiersprachen bestand, dass ein einfaches Aufspielen auf einen neuen Server keine Lösung war.[1] [2]

                  Um überhaupt kommunizieren zu können, startete @Felix Riesterer eine Diskussion in den Kommentaren des Wordpress-Blog.

                  CK programmierte dann das CForum, dass auf einem neuen Server startete. Interessant, dass Doku und Wiki weiter erreichbar waren.

                  Herzliche Grüße

                  Matthias Scharwies

                  --
                  Eigentlich hatte ich heute viel vor - jetzt habe ich morgen viel vor!

                  1. https://blog.selfhtml.org/2012/apr/25/status-des-forumservers ↩︎

                  2. https://blog.selfhtml.org/2012/apr/25/status-des-forumservers#m1782569 ↩︎

                  1. Hallo

                    Allerdings zeigte sich, dass die Software aus so vielen Schichten in allen möglichen Programmiersprachen bestand, dass ein einfaches Aufspielen auf einen neuen Server keine Lösung war.[1] [2]

                    Um überhaupt kommunizieren zu können, startete @Felix Riesterer eine Diskussion in den Kommentaren des Wordpress-Blog.

                    Zusätzlich hat er noch eine Installation von My Little Forum 2 bereitgestellt. Irgendwie passte die Wahl der vorläufigen Software, schließlich startete deren Entwicklung mit einem SELF-Aktuell-Artikel über das Speichern und Auslesen von threadbasierten Strukturen und wurde hier im Forum anfangs intensiv begleitet.

                    Tschö, Auge

                    --
                    200 ist das neue 35.

                    1. https://blog.selfhtml.org/2012/apr/25/status-des-forumservers ↩︎

                    2. https://blog.selfhtml.org/2012/apr/25/status-des-forumservers#m1782569 ↩︎

    2. @@Rolf B

      … mach es so:

      const toogleScrollButtonsThrottled = throttle(toogleScrollButtons, 200);
      

      Jetzt gehen nur die Pfeile nicht mehr weg.

      Ja, das deckt sich mit dem Ergebnis dieser einfacheren Implementierung.

      Wieso eigentlich. Warum findest Du es so schlimm, dass das hidden-Flag zu oft zugewiesen wird? Solange sich das Flag seinen Wert nicht ändert, dürfte das im Browser keine Aktion hervorrufen. Ohne Throttle scheint der Pen ganz prima zu funktionieren.

      Und wenn die Vermeidung der öfteren Ausführung mehr Performance kostet als die eigentliche Ausführung, ist die Vermeidung für die Katz. Mal sehen, vielleicht bleib ich bei requestAnimationFrame.

      🖖 Живіть довго і процвітайте

      --
      „Im Vergleich mit Elon Musk bei Twitter ist ein Elefant im Porzellanladen eine Ballerina.“
      — @Grantscheam auf Twitter
    3. @@Rolf B

      Wieso eigentlich. Warum findest Du es so schlimm, dass das hidden-Flag zu oft zugewiesen wird? Solange sich das Flag seinen Wert nicht ändert, dürfte das im Browser keine Aktion hervorrufen.

      Die linke Seite ist nicht das Problem; die rechte ist es: das Ermitteln der gerade aktuellen Werte von menuULElement.scrollLeft, menuULElement.offsetWidth und menuULElement.scrollWidth. Das will man nicht öfter als nötig tun.

      🖖 Живіть довго і процвітайте

      --
      „Im Vergleich mit Elon Musk bei Twitter ist ein Elefant im Porzellanladen eine Ballerina.“
      — @Grantscheam auf Twitter
      1. Hallo Gunnar,

        Hast du im Profiler feststellen können, dass die Reflows hier ein Problem sind? Nicht jede Abfrage der "bösen" Eigenschaften triggert wirklich einen Reflow. Gerade in einem scroll Event sollte man doch meinen, dass der Browser alles durchgespült hat was nötig ist.

        Rolf

        --
        sumpsi - posui - obstruxi
  2. Hallo, Gunnar,

    Mit Debouncing funktioniert’s, liefert aber nicht das gewünschte Ergebnis: Das Ein-/Ausblenden eines Pfeils erfolgt erst eine gewisse Zeit, nachdem man mit Scrollen aufgehört hat, nicht schon währenddessen.

    wie wäre es mit einem Audit? Dies sollte immer nach der festgelegten Zeit feuern (wenn es denn ein Input-Event gab), auch wenn das letzte Event jünger ist als die festgelegte Zeit.

    Viele Grüße Matti

    1. Hallo Matti,

      diese Audit-Funktion ist ein debouncer, wenn ich das richtig lese.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Hallo,

        diese Audit-Funktion ist ein debouncer, wenn ich das richtig lese.

        nein. Der Debouncer verschiebt den tatsächlichen Auslösezeitpunkt mit jedem eintreffendem Event wieder auf den Threshold. Audit (genau wie throttle) legt den Auslösezeitpunkt beim ersten eintreffenden Event (im aktuellen Fenster) fest - d.h. man erreicht das gewünschte Verhalten, dass nach einer definierten Zeit spätestens ein Event abgearbeitet wird.

        Audit ist dahingehend ein Throttle, nur dass beim Audit das letzte einkommende Event ausgelöst wird und beim Throttle das erste (zumindest in der rxjs-Implementierung). Schau dir dazu mal das Bild bei audit an im Vergleich zu debounce und throttle (ich habe hier mit Absicht die *time-Varianten verlinkt, da Gunnar die dynamische Auslösezeit wsl nicht benötigt).

        VG Matti