2  * jQuery throttle / debounce - v1.1 - 3/7/2010
 
   3  * http://benalman.com/projects/jquery-throttle-debounce-plugin/
 
   5  * Copyright (c) 2010 "Cowboy" Ben Alman
 
   6  * Dual licensed under the MIT and GPL licenses.
 
   7  * http://benalman.com/about/license/
 
  10 // Script: jQuery throttle / debounce: Sometimes, less is more!
 
  12 // *Version: 1.1, Last updated: 3/7/2010*
 
  14 // Project Home - http://benalman.com/projects/jquery-throttle-debounce-plugin/
 
  15 // GitHub       - http://github.com/cowboy/jquery-throttle-debounce/
 
  16 // Source       - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.js
 
  17 // (Minified)   - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.min.js (0.7kb)
 
  21 // Copyright (c) 2010 "Cowboy" Ben Alman,
 
  22 // Dual licensed under the MIT and GPL licenses.
 
  23 // http://benalman.com/about/license/
 
  27 // These working examples, complete with fully commented code, illustrate a few
 
  28 // ways in which this plugin can be used.
 
  30 // Throttle - http://benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/
 
  31 // Debounce - http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/
 
  33 // About: Support and Testing
 
  35 // Information about what version or versions of jQuery this plugin has been
 
  36 // tested with, what browsers it has been tested in, and where the unit tests
 
  37 // reside (so you can test it yourself).
 
  39 // jQuery Versions - none, 1.3.2, 1.4.2
 
  40 // Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome 4-5, Opera 9.6-10.1.
 
  41 // Unit Tests      - http://benalman.com/code/projects/jquery-throttle-debounce/unit/
 
  43 // About: Release History
 
  45 // 1.1 - (3/7/2010) Fixed a bug in <jQuery.throttle> where trailing callbacks
 
  46 //       executed later than they should. Reworked a fair amount of internal
 
  48 // 1.0 - (3/6/2010) Initial release as a stand-alone project. Migrated over
 
  49 //       from jquery-misc repo v0.4 to jquery-throttle repo v1.0, added the
 
  50 //       no_trailing throttle parameter and debounce functionality.
 
  52 // Topic: Note for non-jQuery users
 
  54 // jQuery isn't actually required for this plugin, because nothing internal
 
  55 // uses any jQuery methods or properties. jQuery is just used as a namespace
 
  56 // under which these methods can exist.
 
  58 // Since jQuery isn't actually required for this plugin, if jQuery doesn't exist
 
  59 // when this plugin is loaded, the method described below will be created in
 
  60 // the `Cowboy` namespace. Usage will be exactly the same, but instead of
 
  61 // $.method() or jQuery.method(), you'll need to use Cowboy.method().
 
  63 (function(window,undefined){
 
  64   '$:nomunge'; // Used by YUI compressor.
 
  66   // Since jQuery really isn't required for this plugin, use `jQuery` as the
 
  67   // namespace only if it already exists, otherwise use the `Cowboy` namespace,
 
  68   // creating it if necessary.
 
  69   var $ = window.jQuery || window.Cowboy || ( window.Cowboy = {} ),
 
  71     // Internal method reference.
 
  74   // Method: jQuery.throttle
 
  76   // Throttle execution of a function. Especially useful for rate limiting
 
  77   // execution of handlers on events like resize and scroll. If you want to
 
  78   // rate-limit execution of a function to a single time, see the
 
  79   // <jQuery.debounce> method.
 
  81   // In this visualization, | is a throttled-function call and X is the actual
 
  82   // callback execution:
 
  84   // > Throttled with `no_trailing` specified as false or unspecified:
 
  85   // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
 
  86   // > X    X    X    X    X    X        X    X    X    X    X    X
 
  88   // > Throttled with `no_trailing` specified as true:
 
  89   // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
 
  90   // > X    X    X    X    X             X    X    X    X    X
 
  94   // > var throttled = jQuery.throttle( delay, [ no_trailing, ] callback );
 
  96   // > jQuery('selector').bind( 'someevent', throttled );
 
  97   // > jQuery('selector').unbind( 'someevent', throttled );
 
  99   // This also works in jQuery 1.4+:
 
 101   // > jQuery('selector').bind( 'someevent', jQuery.throttle( delay, [ no_trailing, ] callback ) );
 
 102   // > jQuery('selector').unbind( 'someevent', callback );
 
 106   //  delay - (Number) A zero-or-greater delay in milliseconds. For event
 
 107   //    callbacks, values around 100 or 250 (or even higher) are most useful.
 
 108   //  no_trailing - (Boolean) Optional, defaults to false. If no_trailing is
 
 109   //    true, callback will only execute every `delay` milliseconds while the
 
 110   //    throttled-function is being called. If no_trailing is false or
 
 111   //    unspecified, callback will be executed one final time after the last
 
 112   //    throttled-function call. (After the throttled-function has not been
 
 113   //    called for `delay` milliseconds, the internal counter is reset)
 
 114   //  callback - (Function) A function to be executed after delay milliseconds.
 
 115   //    The `this` context and all arguments are passed through, as-is, to
 
 116   //    `callback` when the throttled-function is executed.
 
 120   //  (Function) A new, throttled, function.
 
 122   $.throttle = jq_throttle = function( delay, no_trailing, callback, debounce_mode ) {
 
 123     // After wrapper has stopped being called, this timeout ensures that
 
 124     // `callback` is executed at the proper times in `throttle` and `end`
 
 128       // Keep track of the last time `callback` was executed.
 
 131     // `no_trailing` defaults to falsy.
 
 132     if ( typeof no_trailing !== 'boolean' ) {
 
 133       debounce_mode = callback;
 
 134       callback = no_trailing;
 
 135       no_trailing = undefined;
 
 138     // The `wrapper` function encapsulates all of the throttling / debouncing
 
 139     // functionality and when executed will limit the rate at which `callback`
 
 143         elapsed = +new Date() - last_exec,
 
 146       // Execute `callback` and update the `last_exec` timestamp.
 
 148         last_exec = +new Date();
 
 149         callback.apply( that, args );
 
 152       // If `debounce_mode` is true (at_begin) this is used to clear the flag
 
 153       // to allow future `callback` executions.
 
 155         timeout_id = undefined;
 
 158       if ( debounce_mode && !timeout_id ) {
 
 159         // Since `wrapper` is being called for the first time and
 
 160         // `debounce_mode` is true (at_begin), execute `callback`.
 
 164       // Clear any existing timeout.
 
 165       timeout_id && clearTimeout( timeout_id );
 
 167       if ( debounce_mode === undefined && elapsed > delay ) {
 
 168         // In throttle mode, if `delay` time has been exceeded, execute
 
 172       } else if ( no_trailing !== true ) {
 
 173         // In trailing throttle mode, since `delay` time has not been
 
 174         // exceeded, schedule `callback` to execute `delay` ms after most
 
 177         // If `debounce_mode` is true (at_begin), schedule `clear` to execute
 
 180         // If `debounce_mode` is false (at end), schedule `callback` to
 
 181         // execute after `delay` ms.
 
 182         timeout_id = setTimeout( debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay );
 
 186     // Set the guid of `wrapper` function to the same of original callback, so
 
 187     // it can be removed in jQuery 1.4+ .unbind or .die by using the original
 
 188     // callback as a reference.
 
 190       wrapper.guid = callback.guid = callback.guid || $.guid++;
 
 193     // Return the wrapper function.
 
 197   // Method: jQuery.debounce
 
 199   // Debounce execution of a function. Debouncing, unlike throttling,
 
 200   // guarantees that a function is only executed a single time, either at the
 
 201   // very beginning of a series of calls, or at the very end. If you want to
 
 202   // simply rate-limit execution of a function, see the <jQuery.throttle>
 
 205   // In this visualization, | is a debounced-function call and X is the actual
 
 206   // callback execution:
 
 208   // > Debounced with `at_begin` specified as false or unspecified:
 
 209   // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
 
 212   // > Debounced with `at_begin` specified as true:
 
 213   // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
 
 218   // > var debounced = jQuery.debounce( delay, [ at_begin, ] callback );
 
 220   // > jQuery('selector').bind( 'someevent', debounced );
 
 221   // > jQuery('selector').unbind( 'someevent', debounced );
 
 223   // This also works in jQuery 1.4+:
 
 225   // > jQuery('selector').bind( 'someevent', jQuery.debounce( delay, [ at_begin, ] callback ) );
 
 226   // > jQuery('selector').unbind( 'someevent', callback );
 
 230   //  delay - (Number) A zero-or-greater delay in milliseconds. For event
 
 231   //    callbacks, values around 100 or 250 (or even higher) are most useful.
 
 232   //  at_begin - (Boolean) Optional, defaults to false. If at_begin is false or
 
 233   //    unspecified, callback will only be executed `delay` milliseconds after
 
 234   //    the last debounced-function call. If at_begin is true, callback will be
 
 235   //    executed only at the first debounced-function call. (After the
 
 236   //    throttled-function has not been called for `delay` milliseconds, the
 
 237   //    internal counter is reset)
 
 238   //  callback - (Function) A function to be executed after delay milliseconds.
 
 239   //    The `this` context and all arguments are passed through, as-is, to
 
 240   //    `callback` when the debounced-function is executed.
 
 244   //  (Function) A new, debounced, function.
 
 246   $.debounce = function( delay, at_begin, callback ) {
 
 247     return callback === undefined
 
 248       ? jq_throttle( delay, at_begin, false )
 
 249       : jq_throttle( delay, callback, at_begin !== false );