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';
|
12 | define(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); });
|