スクロールやテキストエリアの入力等、比較的大量になりやすいイベントをJavaScriptを使ってハンドリングして、さらにサーバーサイドにリクエストを投げたりしているとクライアントサイドだけでなくバックエンドの負荷が高まるのでイベント発火の頻度を抑制したいと思うこともあるかと思います。
そんなときにsetTimeout
を使うとイベントの発火頻度を抑制出来ると知ったので、そのへんのやり方をメモしておきます📝
やりかた
今回はscroll
イベントを検知するような以下のコードで考えていこうと思います。
document.addEventListener('scroll', () => { console.log('scroll!!') })
現状だと非常に大量のイベントが発火してしまいます🔥
ではsetTimeout
を使ってイベント発火を抑制してみます。
まずはイベント発火の抑制の仕組みを持つ以下のような処理を用意します。
let timer = null export const suppression = (callback, interval) => { if (timer) clearTimeout(timer); timer = window.setTimeout(callback, interval); }
流れを説明するとsetTimeout
を管理するtimer
という変数を持ちます。
suppression
という名前で関数を公開し、その中ではtimer
があればtimer
で管理しているsetTimeout
をクリアして、なければsetTimeout
でcallbackで渡された処理を引数で渡されたinteval
分遅延して実行しています。
つまりcallback
で渡された処理が遅延されている場合はsetTimeout
がクリアされるので実行がキャンセルされ、最後に発生したsetTimeout
のみが実行されるわけですね👩🚒
以下が実際に使ってみたサンプルです。scroll
イベントはスクロール中断続的に発火するものの、addEventListener
で指定したcallback
は最後に発生したscroll
イベントでしか実行されません。
import { suppression } from './suppression.js' const INTERVAL_MILLISECOND = 200 document.addEventListener('scroll', () => { suppression(() => { console.log('scroll!!') }, INTERVAL_MILLISECOND) })
おわりに
イベント抑制の仕組みを使うと、ハンドリングして外部のサービスを利用しているような処理を実行しているようなケースがあった場合に、
なんかしらの理由から悪意のあるユーザーにハンドリングしているイベントが知られたときにconsoleから大量実行されて外部サービスのRate Limitに引っかかってサービス全体が利用出来なくなるようなことにも多少は対策になるような気もするので、イベントに依存した処理の実行時には注意したいですね・・・!
また、setTimeout
以外にもLodash
にはthrottle
というメソッドがあったりといろいろな方法があるみたいです👀