index.js 13 KB

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