UNPKG

modern-async

Version:

A modern tooling library for asynchronous operations using async/await, promises and async generators

89 lines (81 loc) 2.92 kB
import asyncDelay from './asyncDelay.mjs' import assert from 'nanoassert' /** * A class used to spread time or cpu intensive operations on multiple tasks in the event loop in order * to avoid blocking other tasks that may need to be executed. * * It is configured with a trigger time, which represents the maximum amount of time your tasks should * monopolize the event loop. Choosing an appropriate trigger time is both important and hard. If too low * it will impact the performances of your long running algorithm. If too high it will impact the other * tasks that need to run in the event loop. * * When using Delayer your code should contain frequent calls to `await delayer.checkDelay()`, usually * at the end of every loop. `checkDelay()` will check the amount of time that ellasped since the last time * it triggered a new task in the event loop. If the amount of time is below the trigger time it returns * an already resolved promise and the remaining computation will be able to continue processing in a * microtask. If not it will call the `asyncDelay()` function that will retrigger the operation in a later task * of the event loop. * * @example * import { Delayer } from 'modern-async' * * const delayer = new Delayer(10) // a delayer with 10ms trigger time * * // some cpu intensive operation that will run for a long time * for (let i = 0; i < 100000000; i += 1) { * // some code * await delayer.checkDelay() * } */ class Delayer { /** * Constructs a new `Delayer` by specifying its trigger time. * * @param {number} triggerTime The trigger time. */ constructor (triggerTime) { this.triggerTime = triggerTime this.reset() } /** * The trigger time of this `Delayer` in milliseconds. The trigger time represent the * maximum amount of time before a call to `checkDelay()` decide to schedule a new task in the event loop. * * @member {number} * @returns {number} ignore */ get triggerTime () { return this._triggerTime } /** * @ignore * @param {number} triggerTime ignore */ set triggerTime (triggerTime) { assert(typeof triggerTime === 'number', 'trigger time must be a number') this._triggerTime = triggerTime } /** * Resets the internal timer to the current time. */ reset () { this._last = new Date().getTime() } /** * Checks if a delay must be applied according to the internal timer. If that's the case this method * will call `asyncDelay()` and return `true`. If not it will do nothing and return `false`. * * @returns {boolean} `true` if a new task was scheduled in the event loop, `false` otherwise. */ async checkDelay () { const current = new Date().getTime() if (current - this._last >= this.triggerTime) { await asyncDelay() this.reset() return true } else { return false } } } export default Delayer