modern-async
Version:
A modern tooling library for asynchronous operations using async/await, promises and async generators
79 lines (73 loc) • 2.54 kB
JavaScript
import assert from 'nanoassert'
import asyncSleepCancellable from './asyncSleepCancellable.mjs'
import Deferred from './Deferred.mjs'
/**
* Waits a given amount of time.
*
* This function returns both a promise and cancel function in order to cancel the
* wait time if necessary. If cancelled, the promise will be rejected with a `CancelledError`.
*
* This function is similar to `asyncSleep()` except it ensures that the amount of time measured
* using the `Date` object is always greater than or equal the asked amount of time.
*
* This function can imply additional delay that can be bad for performances. As such it is
* recommended to only use it in unit tests or very specific cases. Most applications should
* be adapted to work with the usual `setTimout()` inconsistencies even if it can trigger some
* milliseconds before the asked delay.
*
* @param {number} amount An amount of time in milliseconds
* @returns {Array} A tuple of two objects:
* * `promise`: The promise
* * `cancel`: The cancel function. It will return a boolean that will be `true` if the promise was effectively cancelled,
* `false` otherwise.
* @example
* import { asyncSleepPreciseCancellable } from 'modern-async'
*
* const [promise, cancel] = asyncSleepPreciseCancellable(100) // schedule to resolve the promise after 100ms
*
* cancel()
*
* try {
* await promise
* } catch (e) {
* console.log(e.name) // prints CancelledError
* }
*/
function asyncSleepPreciseCancellable (amount) {
return _innerWaitPreciseCancellable(amount, (ellasped, amount) => {
return ellasped >= amount
})
}
export default asyncSleepPreciseCancellable
/**
* @ignore
* @param {*} amount ignored
* @param {*} checkPassed ignored
* @returns {*} ignored
*/
function _innerWaitPreciseCancellable (amount, checkPassed) {
assert(typeof amount === 'number', 'amount must be a number')
const start = new Date().getTime()
const [p, cancel] = asyncSleepCancellable(amount)
let lastCancel = cancel
const deferred = new Deferred()
const reject = (e) => {
deferred.reject(e)
}
const resolve = () => {
const now = new Date().getTime()
const ellasped = now - start
if (checkPassed(ellasped, amount)) {
deferred.resolve()
} else {
const [np, ncancel] = asyncSleepCancellable(amount - ellasped)
lastCancel = ncancel
np.then(resolve, reject)
}
}
p.then(resolve, reject)
return [deferred.promise, () => {
return lastCancel()
}]
}
export { _innerWaitPreciseCancellable }