114 lines
3.1 KiB
JavaScript
114 lines
3.1 KiB
JavaScript
/** @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 work function on the msec delay. The result of
|
|
* the work 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 work 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 work {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 [delayInitialWork] {boolean} if truthy, the first vote is scheduled
|
|
* instead of immediate
|
|
*
|
|
* @returns {Promise}
|
|
*/
|
|
return function poll(work, interval, verifier, delayInitialWork) {
|
|
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(work(),
|
|
function (result) {
|
|
when(verifier(result),
|
|
function (verification) {
|
|
return verification ? certify(result) : schedule(result);
|
|
},
|
|
function () { schedule(result); }
|
|
);
|
|
},
|
|
reject
|
|
);
|
|
}
|
|
|
|
if (delayInitialWork) {
|
|
schedule();
|
|
} else {
|
|
// if work() 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); });
|