poll.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /** @license MIT License (c) copyright 2012-2013 original author or authors */
  2. /**
  3. * poll.js
  4. *
  5. * Helper that polls until cancelled or for a condition to become true.
  6. *
  7. * @author Scott Andrews
  8. */
  9. (function (define) { 'use strict';
  10. define(function(require) {
  11. var when = require('./when');
  12. var attempt = when['try'];
  13. var cancelable = require('./cancelable');
  14. /**
  15. * Periodically execute the task function on the msec delay. The result of
  16. * the task may be verified by watching for a condition to become true. The
  17. * returned deferred is cancellable if the polling needs to be cancelled
  18. * externally before reaching a resolved state.
  19. *
  20. * The next vote is scheduled after the results of the current vote are
  21. * verified and rejected.
  22. *
  23. * Polling may be terminated by the verifier returning a truthy value,
  24. * invoking cancel() on the returned promise, or the task function returning
  25. * a rejected promise.
  26. *
  27. * Usage:
  28. *
  29. * var count = 0;
  30. * function doSomething() { return count++ }
  31. *
  32. * // poll until cancelled
  33. * var p = poll(doSomething, 1000);
  34. * ...
  35. * p.cancel();
  36. *
  37. * // poll until condition is met
  38. * poll(doSomething, 1000, function(result) { return result > 10 })
  39. * .then(function(result) { assert result == 10 });
  40. *
  41. * // delay first vote
  42. * poll(doSomething, 1000, anyFunc, true);
  43. *
  44. * @param task {Function} function that is executed after every timeout
  45. * @param interval {number|Function} timeout in milliseconds
  46. * @param [verifier] {Function} function to evaluate the result of the vote.
  47. * May return a {Promise} or a {Boolean}. Rejecting the promise or a
  48. * falsey value will schedule the next vote.
  49. * @param [delayInitialTask] {boolean} if truthy, the first vote is scheduled
  50. * instead of immediate
  51. *
  52. * @returns {Promise}
  53. */
  54. return function poll(task, interval, verifier, delayInitialTask) {
  55. var deferred, canceled, reject;
  56. canceled = false;
  57. deferred = cancelable(when.defer(), function () { canceled = true; });
  58. reject = deferred.reject;
  59. verifier = verifier || function () { return false; };
  60. if (typeof interval !== 'function') {
  61. interval = (function (interval) {
  62. return function () { return when().delay(interval); };
  63. })(interval);
  64. }
  65. function certify(result) {
  66. deferred.resolve(result);
  67. }
  68. function schedule(result) {
  69. attempt(interval).then(vote, reject);
  70. if (result !== void 0) {
  71. deferred.notify(result);
  72. }
  73. }
  74. function vote() {
  75. if (canceled) { return; }
  76. when(task(),
  77. function (result) {
  78. when(verifier(result),
  79. function (verification) {
  80. return verification ? certify(result) : schedule(result);
  81. },
  82. function () { schedule(result); }
  83. );
  84. },
  85. reject
  86. );
  87. }
  88. if (delayInitialTask) {
  89. schedule();
  90. } else {
  91. // if task() is blocking, vote will also block
  92. vote();
  93. }
  94. // make the promise cancelable
  95. deferred.promise = Object.create(deferred.promise);
  96. deferred.promise.cancel = deferred.cancel;
  97. return deferred.promise;
  98. };
  99. });
  100. })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });