| /** @license MIT License (c) copyright 2012-2013 original author or authors */ |
| |
| /** |
| * poll.js |
| * |
| * Helper that polls until cancelled or for a condition to become true. |
| * |
| * @author Scott Andrews |
| */ |
| |
| (function (define) { 'use strict'; |
| define(function(require) { |
| |
| var when = require('./when'); |
| var attempt = when['try']; |
| var cancelable = require('./cancelable'); |
| |
| /** |
| * Periodically execute the task function on the msec delay. The result of |
| * the task may be verified by watching for a condition to become true. The |
| * returned deferred is cancellable if the polling needs to be cancelled |
| * externally before reaching a resolved state. |
| * |
| * The next vote is scheduled after the results of the current vote are |
| * verified and rejected. |
| * |
| * Polling may be terminated by the verifier returning a truthy value, |
| * invoking cancel() on the returned promise, or the task function returning |
| * a rejected promise. |
| * |
| * Usage: |
| * |
| * var count = 0; |
| * function doSomething() { return count++ } |
| * |
| * // poll until cancelled |
| * var p = poll(doSomething, 1000); |
| * ... |
| * p.cancel(); |
| * |
| * // poll until condition is met |
| * poll(doSomething, 1000, function(result) { return result > 10 }) |
| * .then(function(result) { assert result == 10 }); |
| * |
| * // delay first vote |
| * poll(doSomething, 1000, anyFunc, true); |
| * |
| * @param task {Function} function that is executed after every timeout |
| * @param interval {number|Function} timeout in milliseconds |
| * @param [verifier] {Function} function to evaluate the result of the vote. |
| * May return a {Promise} or a {Boolean}. Rejecting the promise or a |
| * falsey value will schedule the next vote. |
| * @param [delayInitialTask] {boolean} if truthy, the first vote is scheduled |
| * instead of immediate |
| * |
| * @returns {Promise} |
| */ |
| return function poll(task, interval, verifier, delayInitialTask) { |
| var deferred, canceled, reject; |
| |
| canceled = false; |
| deferred = cancelable(when.defer(), function () { canceled = true; }); |
| reject = deferred.reject; |
| |
| verifier = verifier || function () { return false; }; |
| |
| if (typeof interval !== 'function') { |
| interval = (function (interval) { |
| return function () { return when().delay(interval); }; |
| })(interval); |
| } |
| |
| function certify(result) { |
| deferred.resolve(result); |
| } |
| |
| function schedule(result) { |
| attempt(interval).then(vote, reject); |
| if (result !== void 0) { |
| deferred.notify(result); |
| } |
| } |
| |
| function vote() { |
| if (canceled) { return; } |
| when(task(), |
| function (result) { |
| when(verifier(result), |
| function (verification) { |
| return verification ? certify(result) : schedule(result); |
| }, |
| function () { schedule(result); } |
| ); |
| }, |
| reject |
| ); |
| } |
| |
| if (delayInitialTask) { |
| schedule(); |
| } else { |
| // if task() is blocking, vote will also block |
| vote(); |
| } |
| |
| // make the promise cancelable |
| deferred.promise = Object.create(deferred.promise); |
| deferred.promise.cancel = deferred.cancel; |
| |
| return deferred.promise; |
| }; |
| |
| }); |
| })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); |