Lodashなどのサードパーティーのライブラリーを使わずに、JavaScriptのみでthrottle関数を自作する方法です。
JavaScriptでスクロールイベントなど、連続で繰り返し発火するイベントを使用する際には、負荷を軽減させるためにthrottleやdevounceを使うのは有名です。
いわゆる“間引き処理”に使う機能ですが、throttle1つの為に巨大なライブラリーを読み込むのがイヤだったので、自前で用意する方法を調べました。
Lodash.js等のライブラリーなしでthrottleを自作・用意する方法です。
この記事の目次
JavaScriptでthrottleを自作する方法
当記事をお読みの方は既にご存じかと思いますが、JavaScriptのscrollイベントや、mousemoveイベントはそのまま使用すると画面スクロールやマウスカーソルが動くたびに連続で発火します。
百聞は一見に如かずとも言いますので、簡単なサンプルコードを作ってscrollイベントが連続で発火する様子をGIFにしてみました。
スクロールごとに画面のY座標を表示する簡単なものですが、こんな感じです。
サンプルは処理が軽いコードなので何の問題も起きませんが、ある程度複雑な処理をイベント毎に走らせるとなると、ブラウザに高負荷がかかってスクロールがカクつくなどの問題が出てきます。
そんな時にお世話になるのが処理を一定間隔で間引くthrottleという機能です。
簡単に言えば、scrollイベントのような連続発火するイベントを良い感じのタイミングごとに発火するように調整する機能で、よく「間引き」と言われるものです。
Lodash.jsなしでthrottleを使いたい
さて、ここから本題です。
以前scrollイベントを使って記事の目次の現在地を取得するコードを開発していたのですが、その際throttleを使うのに難儀しました。
というのもthrottleメソッドはlodash.jsなど、サードパーティーのライブラリーの中に同梱されており、このようなライブラリーを使うのが一般的な様子なのです。
throttleの使い方を調べると当たり前のように出てくる下記のようなコード。
window.addEventListener('scroll', _.throttle(fn, 1000));
この_.throttle()
という書き方はlodash.jsの使い方みたいです。
throttle1つを使う為だけにライブラリー丸ごと読み込むのもイヤだなぁ…
と思っていたところ、lodash.jsはNode.jsのnpmコマンドを使ってインストールする必要があるそうで…そもそも共有サーバーなので無理です。
ここらへんでthrottleはサクッと使えるものではないことが判明…意外と面倒です。
まぁjQueryやサードパーティーのライブラリを読み込めばサクッと使えるんですが、サイトが重たくなりそうでイヤ!…という変なこだわりから詰まりました。
JavaScriptのみで書いたthrottleのコード
う~ん困った…と思い途方に暮れていたところ、JavaScriptのみでthrottleを自作してコードを紹介して下さっている方がおられました!
外部リンク
そのサイト様がコチラ(↓)です。
throttleとdebounce|mille-feuille code
実際に使わせていただくことになったコードがこちらです。
function throttle(fn, delay) { let timerId; let lastExecTime = 0; return () => { const context = this; const args = arguments; let elapsedTime = performance.now() - lastExecTime; const execute = () => { fn.apply(context, args); lastExecTime = performance.now(); } if (!timerId) { execute(); } if (timerId) { clearTimeout(timerId); } if (elapsedTime > delay) { execute(); } else { timerId = setTimeout(execute, delay); } } }
まさにこれです!JavaScriptだけでthrottleを用意することができます・w・
コードについては作成者様のサイトをご確認下さい。
今回はthrottle
のコードを使わせていただきましたが、JavaScriptのみでdebounce
を自作するコードも掲載して下さっています。
用意したthrottleを使ってみる
コードの使い方についてはlodash.jsの使い方と同じです。
先ほどのコードを読み込み、throttle(callback, delay)
の形で使います。
function myfunc(){ console.log("スクロールしました!Y座標:" + window.scrollY); } window.addEventListener('scroll', throttle(()=>myfunc(), 1000));
こんな感じです。
もちろん引数1000を変更することで処理間隔を調整することが可能です。
せっかくなのでこちらも実際の動作をGIFにしてみました。
記事冒頭のthrottleを使用していない時と比べると、scrollイベントが間引かれて発火回数が大幅に減少していることは一目瞭然ですね。
一応スクロールイベントなので、煮詰めるならFPS(リフレッシュレート)を設定したり、第三引数に{passive: true}
も設定しておくと良いかもしれません。
const fps = 60; window.addEventListener('scroll', throttle(()=>fn(), 1000 / fps), {passive: true});
FPSはカクつき防止のおまじない程度かも…
また、{passive: true}
もタッチイベントじゃないので多分要りません。
まとめ
以上、scrollイベントなどの処理を間引くための機能であるthrottleを自前で用意する方法でした。
特にこだわりが無ければ、サードパーティーからthrottleを読み込んで使うのもアリですが、throttleやdebounceを単体で使いたい時は自作して用意するのもお勧めです。