lib/amd/src/backoff_timer.js

  1. // This file is part of Moodle - http://moodle.org/
  2. //
  3. // Moodle is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // Moodle is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  15. /**
  16. * A timer that will execute a callback with decreasing frequency. Useful for
  17. * doing polling on the server without overwhelming it with requests.
  18. *
  19. * @module core/backoff_timer
  20. * @copyright 2016 Ryan Wyllie <ryan@moodle.com>
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. define(function() {
  24. /**
  25. * Constructor for the back off timer.
  26. *
  27. * @class
  28. * @param {function} callback The function to execute after each tick
  29. * @param {function} backoffFunction The function to determine what the next timeout value should be
  30. */
  31. var BackoffTimer = function(callback, backoffFunction) {
  32. this.callback = callback;
  33. this.backOffFunction = backoffFunction;
  34. };
  35. /**
  36. * @property {function} callback The function to execute after each tick
  37. */
  38. BackoffTimer.prototype.callback = null;
  39. /**
  40. * @property {function} backoffFunction The function to determine what the next timeout value should be
  41. */
  42. BackoffTimer.prototype.backOffFunction = null;
  43. /**
  44. * @property {int} time The timeout value to use
  45. */
  46. BackoffTimer.prototype.time = null;
  47. /**
  48. * @property {numeric} timeout The timeout identifier
  49. */
  50. BackoffTimer.prototype.timeout = null;
  51. /**
  52. * Generate the next timeout in the back off time sequence
  53. * for the timer.
  54. *
  55. * The back off function is called to calculate the next value.
  56. * It is given the current value and an array of all previous values.
  57. *
  58. * @return {int} The new timeout value (in milliseconds)
  59. */
  60. BackoffTimer.prototype.generateNextTime = function() {
  61. var newTime = this.backOffFunction(this.time);
  62. this.time = newTime;
  63. return newTime;
  64. };
  65. /**
  66. * Stop the current timer and clear the previous time values
  67. *
  68. * @return {object} this
  69. */
  70. BackoffTimer.prototype.reset = function() {
  71. this.time = null;
  72. this.stop();
  73. return this;
  74. };
  75. /**
  76. * Clear the current timeout, if one is set.
  77. *
  78. * @return {object} this
  79. */
  80. BackoffTimer.prototype.stop = function() {
  81. if (this.timeout) {
  82. window.clearTimeout(this.timeout);
  83. this.timeout = null;
  84. }
  85. return this;
  86. };
  87. /**
  88. * Start the current timer by generating the new timeout value and
  89. * starting the ticks.
  90. *
  91. * This function recurses after each tick with a new timeout value
  92. * generated each time.
  93. *
  94. * The callback function is called after each tick.
  95. *
  96. * @return {object} this
  97. */
  98. BackoffTimer.prototype.start = function() {
  99. // If we haven't already started.
  100. if (!this.timeout) {
  101. var time = this.generateNextTime();
  102. this.timeout = window.setTimeout(function() {
  103. this.callback();
  104. // Clear the existing timer.
  105. this.stop();
  106. // Start the next timer.
  107. this.start();
  108. }.bind(this), time);
  109. }
  110. return this;
  111. };
  112. /**
  113. * Reset the timer and start it again from the initial timeout
  114. * values
  115. *
  116. * @return {object} this
  117. */
  118. BackoffTimer.prototype.restart = function() {
  119. return this.reset().start();
  120. };
  121. /**
  122. * Returns an incremental function for the timer.
  123. *
  124. * @param {int} minamount The minimum amount of time we wait before checking
  125. * @param {int} incrementamount The amount to increment the timer by
  126. * @param {int} maxamount The max amount to ever increment to
  127. * @param {int} timeoutamount The timeout to use once we reach the max amount
  128. * @return {function}
  129. */
  130. BackoffTimer.getIncrementalCallback = function(minamount, incrementamount, maxamount, timeoutamount) {
  131. /**
  132. * An incremental function for the timer.
  133. *
  134. * @param {(int|null)} time The current timeout value or null if none set
  135. * @return {int} The new timeout value
  136. */
  137. return function(time) {
  138. if (!time) {
  139. return minamount;
  140. }
  141. // Don't go over the max amount.
  142. if (time + incrementamount > maxamount) {
  143. return timeoutamount;
  144. }
  145. return time + incrementamount;
  146. };
  147. };
  148. return BackoffTimer;
  149. });