31257bae29d2d330382517415f337d46bb3d9758668f365ca42403f5d54a7328d8b7879b6359e4cd8fe8b84836f47bff1ec40e8a3087447320c349dcbb7972 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import requestAnimationFrame from '../shims/requestAnimationFrame.js';
  2. // Defines minimum timeout before adding a trailing call.
  3. const trailingTimeout = 2;
  4. /**
  5. * Creates a wrapper function which ensures that provided callback will be
  6. * invoked only once during the specified delay period.
  7. *
  8. * @param {Function} callback - Function to be invoked after the delay period.
  9. * @param {number} delay - Delay after which to invoke callback.
  10. * @returns {Function}
  11. */
  12. export default function (callback, delay) {
  13. let leadingCall = false,
  14. trailingCall = false,
  15. lastCallTime = 0;
  16. /**
  17. * Invokes the original callback function and schedules new invocation if
  18. * the "proxy" was called during current request.
  19. *
  20. * @returns {void}
  21. */
  22. function resolvePending() {
  23. if (leadingCall) {
  24. leadingCall = false;
  25. callback();
  26. }
  27. if (trailingCall) {
  28. proxy();
  29. }
  30. }
  31. /**
  32. * Callback invoked after the specified delay. It will further postpone
  33. * invocation of the original function delegating it to the
  34. * requestAnimationFrame.
  35. *
  36. * @returns {void}
  37. */
  38. function timeoutCallback() {
  39. requestAnimationFrame(resolvePending);
  40. }
  41. /**
  42. * Schedules invocation of the original function.
  43. *
  44. * @returns {void}
  45. */
  46. function proxy() {
  47. const timeStamp = Date.now();
  48. if (leadingCall) {
  49. // Reject immediately following calls.
  50. if (timeStamp - lastCallTime < trailingTimeout) {
  51. return;
  52. }
  53. // Schedule new call to be in invoked when the pending one is resolved.
  54. // This is important for "transitions" which never actually start
  55. // immediately so there is a chance that we might miss one if change
  56. // happens amids the pending invocation.
  57. trailingCall = true;
  58. } else {
  59. leadingCall = true;
  60. trailingCall = false;
  61. setTimeout(timeoutCallback, delay);
  62. }
  63. lastCallTime = timeStamp;
  64. }
  65. return proxy;
  66. }