1 | /**
|
---|
2 | * lodash (Custom Build) <https://lodash.com/>
|
---|
3 | * Build: `lodash modularize exports="npm" -o ./`
|
---|
4 | * Copyright jQuery Foundation and other contributors <https://jquery.org/>
|
---|
5 | * Released under MIT license <https://lodash.com/license>
|
---|
6 | * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
---|
7 | * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
---|
8 | */
|
---|
9 |
|
---|
10 | /** Used as the `TypeError` message for "Functions" methods. */
|
---|
11 | var FUNC_ERROR_TEXT = 'Expected a function';
|
---|
12 |
|
---|
13 | /** Used as references for various `Number` constants. */
|
---|
14 | var NAN = 0 / 0;
|
---|
15 |
|
---|
16 | /** `Object#toString` result references. */
|
---|
17 | var symbolTag = '[object Symbol]';
|
---|
18 |
|
---|
19 | /** Used to match leading and trailing whitespace. */
|
---|
20 | var reTrim = /^\s+|\s+$/g;
|
---|
21 |
|
---|
22 | /** Used to detect bad signed hexadecimal string values. */
|
---|
23 | var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
|
---|
24 |
|
---|
25 | /** Used to detect binary string values. */
|
---|
26 | var reIsBinary = /^0b[01]+$/i;
|
---|
27 |
|
---|
28 | /** Used to detect octal string values. */
|
---|
29 | var reIsOctal = /^0o[0-7]+$/i;
|
---|
30 |
|
---|
31 | /** Built-in method references without a dependency on `root`. */
|
---|
32 | var freeParseInt = parseInt;
|
---|
33 |
|
---|
34 | /** Detect free variable `global` from Node.js. */
|
---|
35 | var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
|
---|
36 |
|
---|
37 | /** Detect free variable `self`. */
|
---|
38 | var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
|
---|
39 |
|
---|
40 | /** Used as a reference to the global object. */
|
---|
41 | var root = freeGlobal || freeSelf || Function('return this')();
|
---|
42 |
|
---|
43 | /** Used for built-in method references. */
|
---|
44 | var objectProto = Object.prototype;
|
---|
45 |
|
---|
46 | /**
|
---|
47 | * Used to resolve the
|
---|
48 | * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
|
---|
49 | * of values.
|
---|
50 | */
|
---|
51 | var objectToString = objectProto.toString;
|
---|
52 |
|
---|
53 | /* Built-in method references for those with the same name as other `lodash` methods. */
|
---|
54 | var nativeMax = Math.max,
|
---|
55 | nativeMin = Math.min;
|
---|
56 |
|
---|
57 | /**
|
---|
58 | * Gets the timestamp of the number of milliseconds that have elapsed since
|
---|
59 | * the Unix epoch (1 January 1970 00:00:00 UTC).
|
---|
60 | *
|
---|
61 | * @static
|
---|
62 | * @memberOf _
|
---|
63 | * @since 2.4.0
|
---|
64 | * @category Date
|
---|
65 | * @returns {number} Returns the timestamp.
|
---|
66 | * @example
|
---|
67 | *
|
---|
68 | * _.defer(function(stamp) {
|
---|
69 | * console.log(_.now() - stamp);
|
---|
70 | * }, _.now());
|
---|
71 | * // => Logs the number of milliseconds it took for the deferred invocation.
|
---|
72 | */
|
---|
73 | var now = function() {
|
---|
74 | return root.Date.now();
|
---|
75 | };
|
---|
76 |
|
---|
77 | /**
|
---|
78 | * Creates a debounced function that delays invoking `func` until after `wait`
|
---|
79 | * milliseconds have elapsed since the last time the debounced function was
|
---|
80 | * invoked. The debounced function comes with a `cancel` method to cancel
|
---|
81 | * delayed `func` invocations and a `flush` method to immediately invoke them.
|
---|
82 | * Provide `options` to indicate whether `func` should be invoked on the
|
---|
83 | * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
|
---|
84 | * with the last arguments provided to the debounced function. Subsequent
|
---|
85 | * calls to the debounced function return the result of the last `func`
|
---|
86 | * invocation.
|
---|
87 | *
|
---|
88 | * **Note:** If `leading` and `trailing` options are `true`, `func` is
|
---|
89 | * invoked on the trailing edge of the timeout only if the debounced function
|
---|
90 | * is invoked more than once during the `wait` timeout.
|
---|
91 | *
|
---|
92 | * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
---|
93 | * until to the next tick, similar to `setTimeout` with a timeout of `0`.
|
---|
94 | *
|
---|
95 | * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
---|
96 | * for details over the differences between `_.debounce` and `_.throttle`.
|
---|
97 | *
|
---|
98 | * @static
|
---|
99 | * @memberOf _
|
---|
100 | * @since 0.1.0
|
---|
101 | * @category Function
|
---|
102 | * @param {Function} func The function to debounce.
|
---|
103 | * @param {number} [wait=0] The number of milliseconds to delay.
|
---|
104 | * @param {Object} [options={}] The options object.
|
---|
105 | * @param {boolean} [options.leading=false]
|
---|
106 | * Specify invoking on the leading edge of the timeout.
|
---|
107 | * @param {number} [options.maxWait]
|
---|
108 | * The maximum time `func` is allowed to be delayed before it's invoked.
|
---|
109 | * @param {boolean} [options.trailing=true]
|
---|
110 | * Specify invoking on the trailing edge of the timeout.
|
---|
111 | * @returns {Function} Returns the new debounced function.
|
---|
112 | * @example
|
---|
113 | *
|
---|
114 | * // Avoid costly calculations while the window size is in flux.
|
---|
115 | * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
|
---|
116 | *
|
---|
117 | * // Invoke `sendMail` when clicked, debouncing subsequent calls.
|
---|
118 | * jQuery(element).on('click', _.debounce(sendMail, 300, {
|
---|
119 | * 'leading': true,
|
---|
120 | * 'trailing': false
|
---|
121 | * }));
|
---|
122 | *
|
---|
123 | * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
|
---|
124 | * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
|
---|
125 | * var source = new EventSource('/stream');
|
---|
126 | * jQuery(source).on('message', debounced);
|
---|
127 | *
|
---|
128 | * // Cancel the trailing debounced invocation.
|
---|
129 | * jQuery(window).on('popstate', debounced.cancel);
|
---|
130 | */
|
---|
131 | function debounce(func, wait, options) {
|
---|
132 | var lastArgs,
|
---|
133 | lastThis,
|
---|
134 | maxWait,
|
---|
135 | result,
|
---|
136 | timerId,
|
---|
137 | lastCallTime,
|
---|
138 | lastInvokeTime = 0,
|
---|
139 | leading = false,
|
---|
140 | maxing = false,
|
---|
141 | trailing = true;
|
---|
142 |
|
---|
143 | if (typeof func != 'function') {
|
---|
144 | throw new TypeError(FUNC_ERROR_TEXT);
|
---|
145 | }
|
---|
146 | wait = toNumber(wait) || 0;
|
---|
147 | if (isObject(options)) {
|
---|
148 | leading = !!options.leading;
|
---|
149 | maxing = 'maxWait' in options;
|
---|
150 | maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
|
---|
151 | trailing = 'trailing' in options ? !!options.trailing : trailing;
|
---|
152 | }
|
---|
153 |
|
---|
154 | function invokeFunc(time) {
|
---|
155 | var args = lastArgs,
|
---|
156 | thisArg = lastThis;
|
---|
157 |
|
---|
158 | lastArgs = lastThis = undefined;
|
---|
159 | lastInvokeTime = time;
|
---|
160 | result = func.apply(thisArg, args);
|
---|
161 | return result;
|
---|
162 | }
|
---|
163 |
|
---|
164 | function leadingEdge(time) {
|
---|
165 | // Reset any `maxWait` timer.
|
---|
166 | lastInvokeTime = time;
|
---|
167 | // Start the timer for the trailing edge.
|
---|
168 | timerId = setTimeout(timerExpired, wait);
|
---|
169 | // Invoke the leading edge.
|
---|
170 | return leading ? invokeFunc(time) : result;
|
---|
171 | }
|
---|
172 |
|
---|
173 | function remainingWait(time) {
|
---|
174 | var timeSinceLastCall = time - lastCallTime,
|
---|
175 | timeSinceLastInvoke = time - lastInvokeTime,
|
---|
176 | result = wait - timeSinceLastCall;
|
---|
177 |
|
---|
178 | return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
|
---|
179 | }
|
---|
180 |
|
---|
181 | function shouldInvoke(time) {
|
---|
182 | var timeSinceLastCall = time - lastCallTime,
|
---|
183 | timeSinceLastInvoke = time - lastInvokeTime;
|
---|
184 |
|
---|
185 | // Either this is the first call, activity has stopped and we're at the
|
---|
186 | // trailing edge, the system time has gone backwards and we're treating
|
---|
187 | // it as the trailing edge, or we've hit the `maxWait` limit.
|
---|
188 | return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
|
---|
189 | (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
|
---|
190 | }
|
---|
191 |
|
---|
192 | function timerExpired() {
|
---|
193 | var time = now();
|
---|
194 | if (shouldInvoke(time)) {
|
---|
195 | return trailingEdge(time);
|
---|
196 | }
|
---|
197 | // Restart the timer.
|
---|
198 | timerId = setTimeout(timerExpired, remainingWait(time));
|
---|
199 | }
|
---|
200 |
|
---|
201 | function trailingEdge(time) {
|
---|
202 | timerId = undefined;
|
---|
203 |
|
---|
204 | // Only invoke if we have `lastArgs` which means `func` has been
|
---|
205 | // debounced at least once.
|
---|
206 | if (trailing && lastArgs) {
|
---|
207 | return invokeFunc(time);
|
---|
208 | }
|
---|
209 | lastArgs = lastThis = undefined;
|
---|
210 | return result;
|
---|
211 | }
|
---|
212 |
|
---|
213 | function cancel() {
|
---|
214 | if (timerId !== undefined) {
|
---|
215 | clearTimeout(timerId);
|
---|
216 | }
|
---|
217 | lastInvokeTime = 0;
|
---|
218 | lastArgs = lastCallTime = lastThis = timerId = undefined;
|
---|
219 | }
|
---|
220 |
|
---|
221 | function flush() {
|
---|
222 | return timerId === undefined ? result : trailingEdge(now());
|
---|
223 | }
|
---|
224 |
|
---|
225 | function debounced() {
|
---|
226 | var time = now(),
|
---|
227 | isInvoking = shouldInvoke(time);
|
---|
228 |
|
---|
229 | lastArgs = arguments;
|
---|
230 | lastThis = this;
|
---|
231 | lastCallTime = time;
|
---|
232 |
|
---|
233 | if (isInvoking) {
|
---|
234 | if (timerId === undefined) {
|
---|
235 | return leadingEdge(lastCallTime);
|
---|
236 | }
|
---|
237 | if (maxing) {
|
---|
238 | // Handle invocations in a tight loop.
|
---|
239 | timerId = setTimeout(timerExpired, wait);
|
---|
240 | return invokeFunc(lastCallTime);
|
---|
241 | }
|
---|
242 | }
|
---|
243 | if (timerId === undefined) {
|
---|
244 | timerId = setTimeout(timerExpired, wait);
|
---|
245 | }
|
---|
246 | return result;
|
---|
247 | }
|
---|
248 | debounced.cancel = cancel;
|
---|
249 | debounced.flush = flush;
|
---|
250 | return debounced;
|
---|
251 | }
|
---|
252 |
|
---|
253 | /**
|
---|
254 | * Checks if `value` is the
|
---|
255 | * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
|
---|
256 | * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
---|
257 | *
|
---|
258 | * @static
|
---|
259 | * @memberOf _
|
---|
260 | * @since 0.1.0
|
---|
261 | * @category Lang
|
---|
262 | * @param {*} value The value to check.
|
---|
263 | * @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
---|
264 | * @example
|
---|
265 | *
|
---|
266 | * _.isObject({});
|
---|
267 | * // => true
|
---|
268 | *
|
---|
269 | * _.isObject([1, 2, 3]);
|
---|
270 | * // => true
|
---|
271 | *
|
---|
272 | * _.isObject(_.noop);
|
---|
273 | * // => true
|
---|
274 | *
|
---|
275 | * _.isObject(null);
|
---|
276 | * // => false
|
---|
277 | */
|
---|
278 | function isObject(value) {
|
---|
279 | var type = typeof value;
|
---|
280 | return !!value && (type == 'object' || type == 'function');
|
---|
281 | }
|
---|
282 |
|
---|
283 | /**
|
---|
284 | * Checks if `value` is object-like. A value is object-like if it's not `null`
|
---|
285 | * and has a `typeof` result of "object".
|
---|
286 | *
|
---|
287 | * @static
|
---|
288 | * @memberOf _
|
---|
289 | * @since 4.0.0
|
---|
290 | * @category Lang
|
---|
291 | * @param {*} value The value to check.
|
---|
292 | * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
|
---|
293 | * @example
|
---|
294 | *
|
---|
295 | * _.isObjectLike({});
|
---|
296 | * // => true
|
---|
297 | *
|
---|
298 | * _.isObjectLike([1, 2, 3]);
|
---|
299 | * // => true
|
---|
300 | *
|
---|
301 | * _.isObjectLike(_.noop);
|
---|
302 | * // => false
|
---|
303 | *
|
---|
304 | * _.isObjectLike(null);
|
---|
305 | * // => false
|
---|
306 | */
|
---|
307 | function isObjectLike(value) {
|
---|
308 | return !!value && typeof value == 'object';
|
---|
309 | }
|
---|
310 |
|
---|
311 | /**
|
---|
312 | * Checks if `value` is classified as a `Symbol` primitive or object.
|
---|
313 | *
|
---|
314 | * @static
|
---|
315 | * @memberOf _
|
---|
316 | * @since 4.0.0
|
---|
317 | * @category Lang
|
---|
318 | * @param {*} value The value to check.
|
---|
319 | * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
|
---|
320 | * @example
|
---|
321 | *
|
---|
322 | * _.isSymbol(Symbol.iterator);
|
---|
323 | * // => true
|
---|
324 | *
|
---|
325 | * _.isSymbol('abc');
|
---|
326 | * // => false
|
---|
327 | */
|
---|
328 | function isSymbol(value) {
|
---|
329 | return typeof value == 'symbol' ||
|
---|
330 | (isObjectLike(value) && objectToString.call(value) == symbolTag);
|
---|
331 | }
|
---|
332 |
|
---|
333 | /**
|
---|
334 | * Converts `value` to a number.
|
---|
335 | *
|
---|
336 | * @static
|
---|
337 | * @memberOf _
|
---|
338 | * @since 4.0.0
|
---|
339 | * @category Lang
|
---|
340 | * @param {*} value The value to process.
|
---|
341 | * @returns {number} Returns the number.
|
---|
342 | * @example
|
---|
343 | *
|
---|
344 | * _.toNumber(3.2);
|
---|
345 | * // => 3.2
|
---|
346 | *
|
---|
347 | * _.toNumber(Number.MIN_VALUE);
|
---|
348 | * // => 5e-324
|
---|
349 | *
|
---|
350 | * _.toNumber(Infinity);
|
---|
351 | * // => Infinity
|
---|
352 | *
|
---|
353 | * _.toNumber('3.2');
|
---|
354 | * // => 3.2
|
---|
355 | */
|
---|
356 | function toNumber(value) {
|
---|
357 | if (typeof value == 'number') {
|
---|
358 | return value;
|
---|
359 | }
|
---|
360 | if (isSymbol(value)) {
|
---|
361 | return NAN;
|
---|
362 | }
|
---|
363 | if (isObject(value)) {
|
---|
364 | var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
|
---|
365 | value = isObject(other) ? (other + '') : other;
|
---|
366 | }
|
---|
367 | if (typeof value != 'string') {
|
---|
368 | return value === 0 ? value : +value;
|
---|
369 | }
|
---|
370 | value = value.replace(reTrim, '');
|
---|
371 | var isBinary = reIsBinary.test(value);
|
---|
372 | return (isBinary || reIsOctal.test(value))
|
---|
373 | ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
|
---|
374 | : (reIsBadHex.test(value) ? NAN : +value);
|
---|
375 | }
|
---|
376 |
|
---|
377 | module.exports = debounce;
|
---|