Created
November 4, 2017 14:14
-
-
Save mr-moon/d862d15ed250cb8ed6ef0a34a1fef859 to your computer and use it in GitHub Desktop.
clean javascript API for waiting for some condition to be met
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A helper that simplifies waiting for something to happen. It acts like an observer without any | |
* particular observable. So your 'evaluator' function may do anything, untill it's returns non-undefined value | |
* | |
* For example, you may want to "observe" a sessionStorage value regardless of browser support of the | |
* "storage" events. | |
* | |
* @example | |
* ```js | |
* var awaiter = await( | |
* // Evaluator | |
* function() { | |
* return sessionStorage['myid'] === '1' || undefined; | |
* }, | |
* | |
* // Callback | |
* function(id) { | |
* console.log('ok, is see my id in sessionStorage now, and it is (should be 1, isn\'t it?)' + id); | |
* }, | |
* | |
* // how often (in milliseconds) I need to look at sessionStorage? | |
* 100, | |
* | |
* // Do I want to evaluate immediately? | |
* true); | |
* | |
* // If I need to limit expectation time, we can do it. Then value passed to callback function is undefined | |
* awaiter.expireAfter(15000); // 15 seconds | |
* | |
* // whenever I need to cancel it | |
* awaiter.cancel(); | |
* | |
* ``` | |
* | |
* Chaining supported too: | |
* ```js | |
* await(...).expireAfter(1000).cancel(); | |
* ``` | |
* | |
* @param {function} evaluatorFn An evaluator function, that should is executed every tick | |
* @param {function} callbackFn A callback function that is executed after evaluatorFn returns defined | |
* (!== undefined) value. It also gets the value that evaluatorFn has returned | |
* @param {number} interval A time period of time that should pass before next evaluation, in ms | |
* @param {Boolean} [trailing=false] Flag that specifies if initial evaluation happens immediately or after a delay. | |
* true - evaluate first only after the delay, false - evaluate immediately | |
* @return Awaiter Returns evaluation processing function. Exposes 'cancel()' and `expireAfter()`. | |
* @author Alexander Moon <[email protected]> | |
*/ | |
function await(evaluatorFn, callbackFn, interval, trailing) { | |
var result, tickFn, expiresAt; | |
if (!trailing && (result = evaluatorFn()) !== undefined) { | |
callbackFn(result); | |
return /** @type Awaiter */ {cancel: noop, expireAfter: noop}; | |
} | |
/** | |
* @typedef {function} AwaiterExpireAfter | |
* @param {number} ms Specify when to expire. In milliseconds. | |
* @return Awaiter | |
*/ | |
/** | |
* @typedef {function} AwaiterCancel | |
* @return undefined | |
*/ | |
/** | |
* @name Awaiter | |
* @type {function} Awaiter | |
* @property {AwaiterCancel} cancel Cancels the wait | |
* @property {AwaiterExpireAfter} expireAfter Sets the time limit for the awaiter | |
*/ | |
tickFn = function evaluationTickFn() { | |
var result = evaluatorFn(); | |
if (result !== undefined) { | |
tickFn.cancel(); | |
tickFn = undefined; | |
callbackFn(result); | |
} | |
if (expiresAt && expiresAt > new Date().getTime()) { | |
callbackFn(undefined); | |
tickFn.cancel(); | |
} | |
}; | |
tickFn.cancel = function () { | |
clearInterval(tickFn._intervalId); | |
tickFn._intervalId = undefined; | |
result = undefined; | |
tickFn.cancel | |
= tickFn.expireAfter | |
= function () { | |
}; | |
}; | |
tickFn.expireAfter = function (ms) { | |
expiresAt = new Date(new Date().getTime() + ms).getTime(); | |
return tickFn; | |
}; | |
tickFn._intervalId = setInterval(function () { | |
//noinspection JSUnresolvedFunction | |
tickFn.call(tickFn); | |
}, interval); | |
return tickFn; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment