【脱初心者】 throttle / debounceとは? jQueryでresizeやscrollの処理負担を軽減する
本記事では、throttle / debounceの説明・使い方を解説します。
throttle / debounce処理は、間引き処理であり処理を軽くすることができます。
例えばscrollやresizeイベントの処理でthrottle / debounceを使うと大きく処理の軽減ができるため、通常これらのイベント処理ではthrottle / debounceを使うことがほぼ常識となっています。
この記事を書いている僕は、フリーランスのフロントエンドのプログラマーとして、これまで3年以上のWeb制作経験があり、HTMLやCSSのマークアップからJavaScriptのフレームワークであるVue,React,Nuxtなどフロントエンドの開発を得意としています。
この記事では処理の負担を軽減する方法をjQueryプラグインを使った方法で初心者にもわかりやすく説明しています。
具体的には、前回の記事「jQueryで「トップへ戻る」ボタンを実装 【初心者向けのJavaScript・jQuery実装】」で実装した「トップへ戻るボタン」の表示(ページスクロールの度にscrollイベントでボタン表示をするかの判定をしていて無駄)について、throttleやdebounceを追加で実装し、処理が軽減されることを例として説明します。
scrollやresizeイベント処理でthrottleやdebounceを使うと処理の軽減ができて効果抜群です。
throttle / debounceを使いこなせるようになって、ひとつレベルをあげて脱初心者を目指しましょう。
throttle / debounceの概要説明
throttleやdebounceがどういったものなのかをまずは解説します。
その後、後半で実際に実装についてコードと完成サイトを交えた解説を行います。
throttle / debounceは使わなくても問題ないように見えるかもしれません。
簡単なホームページなどに実装するJavaScriptの処理は基本的に単純な処理が多く、あまりthrottle / debounceの効果は実感できないかもしれませんが、scrollやresizeイベントでJavaScriptの処理を複雑に行う場合、throttle / debounceを使った場合と使わない場合ではユーザー操作に体感で影響が出るほど違いが出ます。
本記事では、jQueryのthrottle/debounceプラグインを利用することを前提に進めています。
他にもlodashのthrottle/debounceや、npmに登録されているthrottle-debounceなどがあります。
throttleの原理
throttleは、連続した処理の中で、指定した間隔(今回のプラグインだと遅延ミリ秒ごと)に1回だけ実行します。
具体的な例で説明します。
ページのスクロールで「ページトップへ戻る」ボタンが表示されるような機能の実装をする場合、人間の感覚でスクロールされたと認識された時にボタンが表示されれば問題なく、scrollイベントが発生する毎にボタンを表示するべきかという処理をする必要はないわけです。
▼スクロールでボタン表示のJavaScriptコード例(もと)
$(window).scroll(function() {
if ($(this).scrollTop() > 100) {
$('.backToTop').fadeIn();
} else {
$('.backToTop').fadeOut();
}
});
上記の例でいうと、scrollイベントのイベントハンドラー(コールバック処理)で、ボタンを表示させるかどうかを判定して表示・非表示を制御させる処理では、通常1秒間スクロールした場合、このイベントハンドラーの処理はscrollイベントが発生する度に何度も呼び出されることになります。
これをthrottleを使って250ms(0.25秒)おきに判定させれば、1秒間スクロールした場合、イベントハンドラーの処理は4回で済み、大幅な処理の軽減ができます。
実装例は以下の通りです。
▼throttleを実装した例
$(window).scroll(
$.throttle(250, function() {
if ($(this).scrollTop() > 100) {
$('.backToTop').fadeIn();
} else {
$('.backToTop').fadeOut();
}
})
);
250msに1回表示の判定をすれば、人間の感覚からすると十分であり何も問題はありません。throttleを入れた場合と入れない場合では、処理の重さが明らかに違います。
このように無駄に多く処理してしまっている場合は、throttleを用いることによって、処理の回数を減らして動作を軽くすることができます。
debounceの原理
debounceは、イベントなどが繰り返し呼び出されると、呼び出しの「束」ごとに1回だけイベントハンドラー(コールバック処理)を実行します。
先ほどと同じく、ページのスクロールで「ページトップへ戻る」ボタンが表示されるような機能の実装をする場合の例で、debounceを説明します。
▼スクロールでボタン表示のJavaScriptコード例
$(window).scroll(function() {
if ($(this).scrollTop() > 100) {
$('.backToTop').fadeIn();
} else {
$('.backToTop').fadeOut();
}
});
上記のコードにdebounce処理を加えます。
▼debounceを実装した例
$(window).scroll(
$.debounce(250, function() {
if ($(this).scrollTop() > 100) {
$('.backToTop').fadeIn();
} else {
$('.backToTop').fadeOut();
}
})
);
debounceを使わない時は、1秒間スクロールした時にdebounceイベントが発生する毎に処理が走りますが、debounceを使って判定させればイベントハンドラーの処理は1回で済みます。
今回は表示の判定だけなのであまり問題はありませんが、Ajaxで通信が発生する処理が絡む場合などではdebounceを入れた方が圧倒的に効率がよくなります。
GitHubのサンプルコード
サンプルコードとして、GitHubにコードを上げています。
https://github.com/it-web-life/jquery_throttle_debounce
※「git clone」するか、緑色の「Code」ボタンをクリックして「Download ZIP」をクリックしてダウンロードして中身を解凍してください。
ディレクトリ構成
- 「base」ディレクトリ以下:
throttle/debounce実装前のスクロールで「トップへ戻るボタン」が表示されるコードです。 - 「complete_throttle」ディレクトリ以下:
throttleを実装したコードです。 - 「complete_debounce」ディレクトリ以下:
debounceを実装したコードです。
「base」ディレクトリをベースに、追記して実装していきます。
実装前の動作は以下の通りです。
https://it-web-life.github.io/jquery_throttle_debounce/base/index.html
throttle処理の実装
実際にthrottleを実装する例を具体的に解説していきます。
index.html でjQuery本体を読み込んで、処理を書いているscript.jsを読み込んでいる箇所があります。
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="script/script.js"></script>
このscriipt.jsの前にjquery-throttle-debounceプラグインを読み込ませます。
※以下のCDNを使っています
https://cdnjs.cloudflare.com/ajax/libs/jquery-throttle-debounce/1.1/jquery.ba-throttle-debounce.js
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-throttle-debounce/1.1/jquery.ba-throttle-debounce.js"></script>
<script src="script/script.js"></script>
次にscript.jsにて、throttle処理を追加します。
▼変更前:もとの処理
// トップへ戻るボタンの表示制御
$(window).scroll(function() {
if ($(this).scrollTop() > 100) {
$('.backToTop').fadeIn();
} else{
$('.backToTop').fadeOut();
}
});
「$(window).scroll(【イベント処理】)
」で処理をしている箇所に「$.throttle(秒数, コールバック関数)
」を入れます。
変更前: $(window).scroll(【イベント処理】)
変更後: $(window).scroll($.throttle(【秒数(ms指定)】, 【イベント処理】))
▼変更後:throttleあり
// トップへ戻るボタン
$(window).scroll(
$.throttle(250, function() {
if ($(this).scrollTop() > 100) {
$('.backToTop').fadeIn();
} else {
$('.backToTop').fadeOut();
}
})
);
目視ではわかりにくいので、250ms指定を5000ms(5秒)などに変えて試してみると、throttleが操作でも実感できると思います。
throttleを実装した完成品は「complete_throttle」ディレクトリの内容になります。
throttleを実装したサンプルのURL
https://it-web-life.github.io/jquery_throttle_debounce/complete_throttle/index.html
debounce処理の実装
debounceは、throttleとほぼ同じ実装になります。同じことになるため、簡単に記載します。
scriipt.jsの前にjquery-throttle-debounceプラグインを読み込ませます。
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-throttle-debounce/1.1/jquery.ba-throttle-debounce.js"></script>
<script src="script/script.js"></script>
「$(window).scroll(【イベント処理】)
」で処理をしている箇所に「$.debounce(秒数, コールバック関数)
」を入れます。
変更前: $(window).scroll(【イベント処理】)
変更後: $(window).scroll($.debounce(【秒数(ms指定)】, 【イベント処理】))
▼変更後:debounceあり
// トップへ戻るボタン
$(window).scroll(
$.debounce(250, function() {
if ($(this).scrollTop() > 100) {
$('.backToTop').fadeIn();
} else {
$('.backToTop').fadeOut();
}
})
);
スクロールをし続けると、スクロール操作を終了して250ms後(目視だとほぼ直後)に1回処理が実行されます。
throttleを実装した完成品は「complete_debounce」ディレクトリの内容になります。
debounceを実装したサンプルのURL
https://it-web-life.github.io/jquery_throttle_debounce/complete_debounce/index.html
【補足】 jQueryのバージョンについて
jQueryのthrottle/debounceプラグインのページでは、jQuery 1.3.2 & 1.4.2でテスト済となっていますが、jQueryのバージョンは気にしなくて問題ないかと思います。
このプラグインの内部ではjQueryメソッドまたはプロパティを使用していなく、名前空間のためにjQueryを使用しているだけなので、内部のコードも見るとわかりますが、jQueryのバージョンは特に動作に影響はないかと思います。
まとめ
throttle / debounce処理は、間引き処理であって、scrollやresizeイベント処理などで処理を軽くすることができます。
「jQueryのthrottle/debounceプラグイン」の実装方法は以下の通りです。
1. jQuery, プラグインを読み込ませる
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-throttle-debounce/1.1/jquery.ba-throttle-debounce.js"></script>
2. throttle, debounceの処理を入れる
throttle: 「$.throttle(秒数, コールバック関数)
」
debounce: 「$.debounce(秒数, コールバック関数)
」
今回の実装では、throttleとdebounceの両方を実装してみましたが、実際にはどちらで実装してもよいと思います。
ページスクロールでトップへ戻るボタンが表示される、今回のような場合は個人的には、throttleで250ms置きに処理が走る形で実装すればよいかと思っています。
throttle/debounceの実装は、WordPress等で実装している初期の頃のレベルだとあまり複雑なJavaScriptを実装することがなく気づかなくて、JavaScriptをゴリゴリ使っているプロジェクトに入って初めて僕も重要さに気づきました。throttle/debounce処理を入れることにより、よりユーザーフレンドリーな実装ができるようになると思います。
以上となります。
ご参考になれば幸いです。
debounce JavaScript jQuery throttle
※当サイトでは一部のリンクについてアフィリエイトプログラムを利用して商品を紹介しています