debounce.js 13 KB

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