UNPKG

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