jQuery(window).resize() を遅延させる(jQuery.throttle / jQuery.debounceのすすめ)

ウィンドウサイズの変更(≒エレメントサイズの変更)を検出して何かするのに、$(window).resize(function(){/* some action */})というのがあります。

しかし、たとえば0.1pxの変更でも、検出されてresizeイベントにbindされたfunctionをtriggerするので、リサイズしているあいだじゅう処理が発生し、多少時間がかかることをしていると、処理がたまってブラウザをハングさせる危険性があります。

そこでこんなものを用意します。

jQuery.throttle/jQuery.debounce

$.extend({
 throttle : function( delay, no_trailing, callback, debounce_mode ) {
  var timeout_id,
    last_exec = 0;
  if ( typeof no_trailing !== 'boolean' ) {
    debounce_mode = callback;
    callback = no_trailing;
    no_trailing = undefined;
  }
  ;
  var wrapper = function() {
   var that = this,
       elapsed = +new Date() - last_exec,
       args = arguments;
   var exec = function() {
    last_exec = +new Date();
    callback.apply( that, args );
   }
   ;
   var clear = function() { timeout_id = undefined }
   
   if ( debounce_mode && !timeout_id ) { exec() }
   timeout_id && clearTimeout( timeout_id );
   if ( debounce_mode === undefined && elapsed > delay ) {
    exec()
   }
   else if ( no_trailing !== true ) {
    timeout_id = setTimeout( debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay );
   }
  }
  ;
  if ( $.guid ) { wrapper.guid = callback.guid = callback.guid || $.guid++; }
  return wrapper;
 },

 debounce : function( delay, at_begin, callback ) {
  return callback === undefined
    ? $.throttle( delay, at_begin, false )
    : $.throttle( delay, callback, at_begin !== false );
 }
});

使い方

/* 例1:throttle */
$(window).bind("resize", $.throttle(500, f1 = function(){/* some action 1 */}));
/* 例2:debounce */
$(window).bind("resize", $.debounce(100, f2 = function(){/* some action 2 */}));

上の例だと、

  • 例1:ウィンドウリサイズ中は f1 は実行されず、リサイズされなくなって500ミリ秒後にf1の内容が実行
  • 例2:ウィンドウのリサイズ中100ミリ秒ごとに f2 の内容が実行

という具合です。

つまり、

  • throttleは、bindされたfunctionを、イベントが発生している間は保留し、発生しなくなってから指定時間(ms)後にtrigger。
  • debounceは、bindされたfunctionを、イベントが発生している間一定時間(ms)間隔でtrigger。

これでresizeイベントで動作が重たくなるのが解決します。

ネタ元:jQuery throttle / debounce: Sometimes, less is more!

Leave a Reply