|
| 1 | +/*! |
| 2 | + * jQuery throttle / debounce - v1.1 - 3/7/2010 |
| 3 | + * http://benalman.com/projects/jquery-throttle-debounce-plugin/ |
| 4 | + * |
| 5 | + * Copyright (c) 2010 "Cowboy" Ben Alman |
| 6 | + * Dual licensed under the MIT and GPL licenses. |
| 7 | + * http://benalman.com/about/license/ |
| 8 | + */ |
| 9 | + |
| 10 | +// Script: jQuery throttle / debounce: Sometimes, less is more! |
| 11 | +// |
| 12 | +// *Version: 1.1, Last updated: 3/7/2010* |
| 13 | +// |
| 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) |
| 18 | +// |
| 19 | +// About: License |
| 20 | +// |
| 21 | +// Copyright (c) 2010 "Cowboy" Ben Alman, |
| 22 | +// Dual licensed under the MIT and GPL licenses. |
| 23 | +// http://benalman.com/about/license/ |
| 24 | +// |
| 25 | +// About: Examples |
| 26 | +// |
| 27 | +// These working examples, complete with fully commented code, illustrate a few |
| 28 | +// ways in which this plugin can be used. |
| 29 | +// |
| 30 | +// Throttle - http://benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/ |
| 31 | +// Debounce - http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/ |
| 32 | +// |
| 33 | +// About: Support and Testing |
| 34 | +// |
| 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). |
| 38 | +// |
| 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/ |
| 42 | +// |
| 43 | +// About: Release History |
| 44 | +// |
| 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 |
| 47 | +// logic as well. |
| 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. |
| 51 | +// |
| 52 | +// Topic: Note for non-jQuery users |
| 53 | +// |
| 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. |
| 57 | +// |
| 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(). |
| 62 | + |
| 63 | +(function(window,undefined){ |
| 64 | + '$:nomunge'; // Used by YUI compressor. |
| 65 | + |
| 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 = {} ), |
| 70 | + |
| 71 | + // Internal method reference. |
| 72 | + jq_throttle; |
| 73 | + |
| 74 | + // Method: jQuery.throttle |
| 75 | + // |
| 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. |
| 80 | + // |
| 81 | + // In this visualization, | is a throttled-function call and X is the actual |
| 82 | + // callback execution: |
| 83 | + // |
| 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 |
| 87 | + // > |
| 88 | + // > Throttled with `no_trailing` specified as true: |
| 89 | + // > ||||||||||||||||||||||||| (pause) ||||||||||||||||||||||||| |
| 90 | + // > X X X X X X X X X X |
| 91 | + // |
| 92 | + // Usage: |
| 93 | + // |
| 94 | + // > var throttled = jQuery.throttle( delay, [ no_trailing, ] callback ); |
| 95 | + // > |
| 96 | + // > jQuery('selector').bind( 'someevent', throttled ); |
| 97 | + // > jQuery('selector').unbind( 'someevent', throttled ); |
| 98 | + // |
| 99 | + // This also works in jQuery 1.4+: |
| 100 | + // |
| 101 | + // > jQuery('selector').bind( 'someevent', jQuery.throttle( delay, [ no_trailing, ] callback ) ); |
| 102 | + // > jQuery('selector').unbind( 'someevent', callback ); |
| 103 | + // |
| 104 | + // Arguments: |
| 105 | + // |
| 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. |
| 117 | + // |
| 118 | + // Returns: |
| 119 | + // |
| 120 | + // (Function) A new, throttled, function. |
| 121 | + |
| 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` |
| 125 | + // debounce modes. |
| 126 | + var timeout_id, |
| 127 | + |
| 128 | + // Keep track of the last time `callback` was executed. |
| 129 | + last_exec = 0; |
| 130 | + |
| 131 | + // `no_trailing` defaults to falsy. |
| 132 | + if ( typeof no_trailing !== 'boolean' ) { |
| 133 | + debounce_mode = callback; |
| 134 | + callback = no_trailing; |
| 135 | + no_trailing = undefined; |
| 136 | + } |
| 137 | + |
| 138 | + // The `wrapper` function encapsulates all of the throttling / debouncing |
| 139 | + // functionality and when executed will limit the rate at which `callback` |
| 140 | + // is executed. |
| 141 | + function wrapper() { |
| 142 | + var that = this, |
| 143 | + elapsed = +new Date() - last_exec, |
| 144 | + args = arguments; |
| 145 | + |
| 146 | + // Execute `callback` and update the `last_exec` timestamp. |
| 147 | + function exec() { |
| 148 | + last_exec = +new Date(); |
| 149 | + callback.apply( that, args ); |
| 150 | + }; |
| 151 | + |
| 152 | + // If `debounce_mode` is true (at_begin) this is used to clear the flag |
| 153 | + // to allow future `callback` executions. |
| 154 | + function clear() { |
| 155 | + timeout_id = undefined; |
| 156 | + }; |
| 157 | + |
| 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`. |
| 161 | + exec(); |
| 162 | + } |
| 163 | + |
| 164 | + // Clear any existing timeout. |
| 165 | + timeout_id && clearTimeout( timeout_id ); |
| 166 | + |
| 167 | + if ( debounce_mode === undefined && elapsed > delay ) { |
| 168 | + // In throttle mode, if `delay` time has been exceeded, execute |
| 169 | + // `callback`. |
| 170 | + exec(); |
| 171 | + |
| 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 |
| 175 | + // recent execution. |
| 176 | + // |
| 177 | + // If `debounce_mode` is true (at_begin), schedule `clear` to execute |
| 178 | + // after `delay` ms. |
| 179 | + // |
| 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 ); |
| 183 | + } |
| 184 | + }; |
| 185 | + |
| 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. |
| 189 | + if ( $.guid ) { |
| 190 | + wrapper.guid = callback.guid = callback.guid || $.guid++; |
| 191 | + } |
| 192 | + |
| 193 | + // Return the wrapper function. |
| 194 | + return wrapper; |
| 195 | + }; |
| 196 | + |
| 197 | + // Method: jQuery.debounce |
| 198 | + // |
| 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> |
| 203 | + // method. |
| 204 | + // |
| 205 | + // In this visualization, | is a debounced-function call and X is the actual |
| 206 | + // callback execution: |
| 207 | + // |
| 208 | + // > Debounced with `at_begin` specified as false or unspecified: |
| 209 | + // > ||||||||||||||||||||||||| (pause) ||||||||||||||||||||||||| |
| 210 | + // > X X |
| 211 | + // > |
| 212 | + // > Debounced with `at_begin` specified as true: |
| 213 | + // > ||||||||||||||||||||||||| (pause) ||||||||||||||||||||||||| |
| 214 | + // > X X |
| 215 | + // |
| 216 | + // Usage: |
| 217 | + // |
| 218 | + // > var debounced = jQuery.debounce( delay, [ at_begin, ] callback ); |
| 219 | + // > |
| 220 | + // > jQuery('selector').bind( 'someevent', debounced ); |
| 221 | + // > jQuery('selector').unbind( 'someevent', debounced ); |
| 222 | + // |
| 223 | + // This also works in jQuery 1.4+: |
| 224 | + // |
| 225 | + // > jQuery('selector').bind( 'someevent', jQuery.debounce( delay, [ at_begin, ] callback ) ); |
| 226 | + // > jQuery('selector').unbind( 'someevent', callback ); |
| 227 | + // |
| 228 | + // Arguments: |
| 229 | + // |
| 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. |
| 241 | + // |
| 242 | + // Returns: |
| 243 | + // |
| 244 | + // (Function) A new, debounced, function. |
| 245 | + |
| 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 ); |
| 250 | + }; |
| 251 | + |
| 252 | +})(this); |
0 commit comments