diff --git a/CHANGELOG.md b/CHANGELOG.md index 66c433b..3611212 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 1.0.4 + +* Fixed bug in `forEachLimit` + ## 1.0.3 * Performance improvements. Notably the `Queue` class will now avoid calling the `delay()` function and will immediately trigger any diff --git a/docs/modern-async/1.0.4/CancelledError.html b/docs/modern-async/1.0.4/CancelledError.html new file mode 100644 index 0000000..a2d0f42 --- /dev/null +++ b/docs/modern-async/1.0.4/CancelledError.html @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CancelledError + + + + + + + + + + + + + + + + + + + +
+ +

CancelledError

+ + + + + + + +
+ + +
+ + +

+ + CancelledError + +

+ + +

An error type which is used when a promise is cancelled.

+
+ + +
+ + +
+
+ + + + +

Constructor

+ + +

+ # + new CancelledError(message) +

+ + + + + +
+

Constructs a new instance.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
message + + +string + + + +

The error message

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/modern-async/1.0.4/CancelledError.mjs.html b/docs/modern-async/1.0.4/CancelledError.mjs.html new file mode 100644 index 0000000..dc2ce38 --- /dev/null +++ b/docs/modern-async/1.0.4/CancelledError.mjs.html @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CancelledError.mjs + + + + + + + + + + + + + + + + + + + +
+ +

CancelledError.mjs

+ + + + + + + +
+
+

+/**
+ * An error type which is used when a promise is cancelled.
+ */
+class CancelledError extends Error {
+  /**
+   * Constructs a new instance.
+   *
+   * @param {string} message The error message
+   */
+  constructor (message) {
+    super(message)
+    this.name = this.constructor.name
+  }
+}
+
+export default CancelledError
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/Deferred.html b/docs/modern-async/1.0.4/Deferred.html new file mode 100644 index 0000000..a35f041 --- /dev/null +++ b/docs/modern-async/1.0.4/Deferred.html @@ -0,0 +1,522 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deferred + + + + + + + + + + + + + + + + + + + +
+ +

Deferred

+ + + + + + + +
+ + +
+ + +

+ + Deferred + +

+ + +

A basic class to create a promise with its resolve and reject function in the same object.

+

Instances of this class are never returned by any function of this library but it is used +internally and can be useful to code other asynchronous helpers.

+
+ + +
+ + +
+
+ + + + +

Constructor

+ + +

+ # + new Deferred() +

+ + + + + +
+

Constructs a deferred object.

+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ Example + +
import { Deferred, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const deferred = new Deferred()
+
+  sleep(10).then(() => {
+    deferred.resolve('test')
+  })
+
+  console.log(await deferred.promise) // will wait 10ms before printing 'test'
+})
+ +
+ + + +
+ + + + + + + + + + + + +

Members

+ + + +

+ # + promise :Promise +

+ + + + +
+

(Read-only) The promise.

+
+ + + +
+ Type: +
    +
  • + +Promise + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + +

+ # + reject :function +

+ + + + +
+

(Read-only) The reject function

+
+ + + +
+ Type: +
    +
  • + +function + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + +

+ # + resolve :function +

+ + + + +
+

(Read-only) The resolve function.

+
+ + + +
+ Type: +
    +
  • + +function + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/modern-async/1.0.4/Deferred.mjs.html b/docs/modern-async/1.0.4/Deferred.mjs.html new file mode 100644 index 0000000..29d0e04 --- /dev/null +++ b/docs/modern-async/1.0.4/Deferred.mjs.html @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deferred.mjs + + + + + + + + + + + + + + + + + + + +
+ +

Deferred.mjs

+ + + + + + + +
+
+

+/**
+ * A basic class to create a promise with its resolve and reject function in the same object.
+ *
+ * Instances of this class are never returned by any function of this library but it is used
+ * internally and can be useful to code other asynchronous helpers.
+ *
+ * @example
+ * import { Deferred, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const deferred = new Deferred()
+ *
+ *   sleep(10).then(() => {
+ *     deferred.resolve('test')
+ *   })
+ *
+ *   console.log(await deferred.promise) // will wait 10ms before printing 'test'
+ * })
+ */
+class Deferred {
+  /**
+   * Constructs a deferred object.
+   */
+  constructor () {
+    this._promise = new Promise((resolve, reject) => {
+      this._resolve = resolve
+      this._reject = reject
+    })
+  }
+
+  /**
+   * (Read-only) The promise.
+   *
+   * @member {Promise}
+   *
+   * @returns {Promise} ignored
+   */
+  get promise () {
+    return this._promise
+  }
+
+  /**
+   * (Read-only) The resolve function.
+   *
+   * @member {Function}
+   *
+   * @returns {Function} The resolve function
+   */
+  get resolve () {
+    return this._resolve
+  }
+
+  /**
+   * (Read-only) The reject function
+   *
+   * @member {Function}
+   *
+   * @returns {Function} The reject function
+   */
+  get reject () {
+    return this._reject
+  }
+}
+
+export default Deferred
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/Delayer.html b/docs/modern-async/1.0.4/Delayer.html new file mode 100644 index 0000000..5d6d1e6 --- /dev/null +++ b/docs/modern-async/1.0.4/Delayer.html @@ -0,0 +1,626 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Delayer + + + + + + + + + + + + + + + + + + + +
+ +

Delayer

+ + + + + + + +
+ + +
+ + +

+ + Delayer + +

+ + +

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 +your called it. If the amount of time is below the trigger time it returns immediately. If not it will +call the delay() function that will retrigger the operation in a later task of the event loop.

+
+ + +
+ + +
+
+ + + + +

Constructor

+ + +

+ # + new Delayer(triggerTime) +

+ + + + + +
+

Constructs a new Delayer by specifying its trigger time.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
triggerTime + + +number + + + +

The trigger time.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ Example + +
import { Delayer, asyncRoot } from 'modern-async'
+
+asyncRoot(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()
+  }
+})
+ +
+ + + +
+ + + + + + + + + + + + +

Members

+ + + +

+ # + triggerTime :number +

+ + + + +
+

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.

+
+ + + +
+ Type: +
    +
  • + +number + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + +

+ # + (async) checkDelay() → {boolean} +

+ + + + + +
+

Checks if a delay must be applied according to the internal timer. If that's the case this method +will call delay() and return true. If not it will do nothing and return false.

+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

true if a new task was scheduled in the event loop, false otherwise.

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ +
+ + + + + + + + + +

+ # + reset() +

+ + + + + +
+

Resets the internal timer to the current time.

+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/modern-async/1.0.4/Delayer.mjs.html b/docs/modern-async/1.0.4/Delayer.mjs.html new file mode 100644 index 0000000..53b2408 --- /dev/null +++ b/docs/modern-async/1.0.4/Delayer.mjs.html @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Delayer.mjs + + + + + + + + + + + + + + + + + + + +
+ +

Delayer.mjs

+ + + + + + + +
+
+

+import delay from './delay.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
+ * your called it. If the amount of time is below the trigger time it returns immediately. If not it will
+ * call the `delay()` function that will retrigger the operation in a later task of the event loop.
+ *
+ * @example
+ * import { Delayer, asyncRoot } from 'modern-async'
+ *
+ * asyncRoot(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 `delay()` 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 delay()
+      this.reset()
+      return true
+    } else {
+      return false
+    }
+  }
+}
+
+export default Delayer
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/Queue.html b/docs/modern-async/1.0.4/Queue.html new file mode 100644 index 0000000..6ef48dd --- /dev/null +++ b/docs/modern-async/1.0.4/Queue.html @@ -0,0 +1,1115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Queue + + + + + + + + + + + + + + + + + + + +
+ +

Queue

+ + + + + + + +
+ + +
+ + +

+ + Queue + +

+ + +

A class representing a queue.

+

Tasks added to the queue are processed in parallel (up to the concurrency limit). +If all slots of the queue are occupied, the task is queued until one becomes available. +When a slot is freed, the pending task with higher priority is executed. If multiple pending tasks have the same +priority the first that was scheduled is executed.

+

Once a task is completed, its corresponding promise is terminated accordingly.

+
+ + +
+ + +
+
+ + + + +

Constructor

+ + +

+ # + new Queue(concurrency) +

+ + + + + +
+

Constructs a queue with the given concurrency

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
concurrency + + +number + + + +

The concurrency of the queue, must be an integer greater than 0 or +Number.POSITIVE_INFINITY.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ Example + +
import { Queue, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const queue = new Queue(3) // create a queue with concurrency 3
+
+  const array = Array.from(Array(100).keys()) // an array of 100 numbers from 0 to 99
+
+  const promises = []
+  for (const i of array) {
+    promises.push(queue.exec(async () => {
+      console.log(`Starting task ${i}`)
+      await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+      console.log(`Ending task ${i}`)
+      return i;
+    }))
+  }
+  const results = await Promise.all(promises)
+  // all the scheduled tasks will perform with a maximum concurrency of 3 and log when they start and stop
+
+  console.log(results) // will display an array with the result of the execution of each separate task
+})
+ +
+ + + +
+ + + + + + + + + + + + +

Members

+ + + +

+ # + concurrency :number +

+ + + + +
+

(Read-only) The concurrency of the queue.

+
+ + + +
+ Type: +
    +
  • + +number + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + +

+ # + pending :number +

+ + + + +
+

(Read-only) The number of pending tasks.

+
+ + + +
+ Type: +
    +
  • + +number + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + +

+ # + running :number +

+ + + + +
+

(Read-only) The current number of tasks that are processing.

+
+ + + +
+ Type: +
    +
  • + +number + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + +

+ # + cancelAllPending() → {number} +

+ + + + + +
+

Cancels all pending tasks. Their corresponding promises will be rejected with a CancelledError. This method will +not alter tasks that are already running.

+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

The number of pending tasks that were effectively cancelled.

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ +
+ + + + + + + + + +

+ # + (async) exec(fct, priority) → {Promise} +

+ + + + + +
+

Puts a task at the end of the queue. When the task is executed and completes the returned promise will be terminated +accordingly.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fct + + +function + + + + + +

An asynchronous functions representing the task. It will be executed when the queue has +available slots and its result will be propagated to the promise returned by exec().

priority + + +number + + + + + + 0 + +

(Optional) The priority of the task. The higher the priority is, the sooner the task will be +executed regarding the priority of other pending tasks. Defaults to 0.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved or rejected once the task has completed. Its state will be the same +than the promise returned by the call to fct.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + + + + + + + +

+ # + execCancellable(fct, priority) → {Array} +

+ + + + + +
+

Puts a task at the end of the queue. When the task is executed and completes the returned promise will be terminated +accordingly.

+

This function returns both a promise and a cancel function. The cancel function allows to cancel the pending task, +but only if it wasn't started yet. Calling the cancel function on a task that it already running has no effect. +When a task is cancelled its corresponding promise will be rejected with a CancelledError.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fct + + +function + + + + + +

An asynchronous functions representing the task. It will be executed when the queue has +available slots and its result will be propagated to the promise returned by exec().

priority + + +number + + + + + + 0 + +

(Optional) The priority of the task. The higher the priority is, the sooner the task will be +executed regarding the priority of other pending tasks. Defaults to 0.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A tuple with two parameters:

+
    +
  • promise: A promise that will be resolved or rejected once the task has completed. Its state will be the same +than the promise returned by the call to fct.
  • +
  • cancel: A cancel function. When called it will cancel the task if it is still pending. It has no effect is the +task has already started or already terminated. When a task is cancelled its corresponding promise will be +rejected with a CancelledError. If will return true if the task was effectively pending and was cancelled, +false in any other case.
  • +
+
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/modern-async/1.0.4/Queue.mjs.html b/docs/modern-async/1.0.4/Queue.mjs.html new file mode 100644 index 0000000..e6c2e33 --- /dev/null +++ b/docs/modern-async/1.0.4/Queue.mjs.html @@ -0,0 +1,481 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Queue.mjs + + + + + + + + + + + + + + + + + + + +
+ +

Queue.mjs

+ + + + + + + +
+
+
import assert from 'nanoassert'
+import Deferred from './Deferred.mjs'
+import asyncWrap from './asyncWrap.mjs'
+import CancelledError from './CancelledError.mjs'
+
+/**
+ * A class representing a queue.
+ *
+ * Tasks added to the queue are processed in parallel (up to the concurrency limit).
+ * If all slots of the queue are occupied, the task is queued until one becomes available.
+ * When a slot is freed, the pending task with higher priority is executed. If multiple pending tasks have the same
+ * priority the first that was scheduled is executed.
+ *
+ * Once a task is completed, its corresponding promise is terminated accordingly.
+ *
+ * @example
+ * import { Queue, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const queue = new Queue(3) // create a queue with concurrency 3
+ *
+ *   const array = Array.from(Array(100).keys()) // an array of 100 numbers from 0 to 99
+ *
+ *   const promises = []
+ *   for (const i of array) {
+ *     promises.push(queue.exec(async () => {
+ *       console.log(`Starting task ${i}`)
+ *       await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+ *       console.log(`Ending task ${i}`)
+ *       return i;
+ *     }))
+ *   }
+ *   const results = await Promise.all(promises)
+ *   // all the scheduled tasks will perform with a maximum concurrency of 3 and log when they start and stop
+ *
+ *   console.log(results) // will display an array with the result of the execution of each separate task
+ * })
+ */
+class Queue {
+  /**
+   * Constructs a queue with the given concurrency
+   *
+   * @param {number} concurrency The concurrency of the queue, must be an integer greater than 0 or
+   * `Number.POSITIVE_INFINITY`.
+   */
+  constructor (concurrency) {
+    assert(Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY,
+      'concurrency must be an integer or positive infinity')
+    assert(concurrency > 0, 'concurrency must be greater than 0')
+    if (concurrency !== Number.POSITIVE_INFINITY) {
+      this._queue = new _InternalQueuePriority(concurrency)
+    } else {
+      this._queue = new _InternalInfinityQueue()
+    }
+  }
+
+  /**
+   * (Read-only) The concurrency of the queue.
+   *
+   * @member {number}
+   *
+   * @returns {number} ignore
+   */
+  get concurrency () {
+    return this._queue.concurrency
+  }
+
+  /**
+   * (Read-only) The current number of tasks that are processing.
+   *
+   * @member {number}
+   *
+   * @returns {number} ignore
+   */
+  get running () {
+    return this._queue.running
+  }
+
+  /**
+   * (Read-only) The number of pending tasks.
+   *
+   * @member {number}
+   *
+   * @returns {number} ignore
+   */
+  get pending () {
+    return this._queue.pending
+  }
+
+  /**
+   * Puts a task at the end of the queue. When the task is executed and completes the returned promise will be terminated
+   * accordingly.
+   *
+   * @param {Function} fct An asynchronous functions representing the task. It will be executed when the queue has
+   * available slots and its result will be propagated to the promise returned by exec().
+   * @param {number} priority (Optional) The priority of the task. The higher the priority is, the sooner the task will be
+   * executed regarding the priority of other pending tasks. Defaults to 0.
+   * @returns {Promise} A promise that will be resolved or rejected once the task has completed. Its state will be the same
+   * than the promise returned by the call to `fct`.
+   */
+  async exec (fct, priority = 0) {
+    return this._queue.exec(fct, priority)
+  }
+
+  /**
+   * Puts a task at the end of the queue. When the task is executed and completes the returned promise will be terminated
+   * accordingly.
+   *
+   * This function returns both a promise and a cancel function. The cancel function allows to cancel the pending task,
+   * but only if it wasn't started yet. Calling the cancel function on a task that it already running has no effect.
+   * When a task is cancelled its corresponding promise will be rejected with a `CancelledError`.
+   *
+   * @param {Function} fct An asynchronous functions representing the task. It will be executed when the queue has
+   * available slots and its result will be propagated to the promise returned by exec().
+   * @param {number} priority (Optional) The priority of the task. The higher the priority is, the sooner the task will be
+   * executed regarding the priority of other pending tasks. Defaults to 0.
+   * @returns {Array} A tuple with two parameters:
+   *   * `promise`: A promise that will be resolved or rejected once the task has completed. Its state will be the same
+   *     than the promise returned by the call to `fct`.
+   *   * `cancel`: A cancel function. When called it will cancel the task if it is still pending. It has no effect is the
+   *     task has already started or already terminated. When a task is cancelled its corresponding promise will be
+   *     rejected with a `CancelledError`. If will return `true` if the task was effectively pending and was cancelled,
+   *     `false` in any other case.
+   */
+  execCancellable (fct, priority = 0) {
+    return this._queue.execCancellable(fct, priority)
+  }
+
+  /**
+   * Cancels all pending tasks. Their corresponding promises will be rejected with a `CancelledError`. This method will
+   * not alter tasks that are already running.
+   *
+   * @returns {number} The number of pending tasks that were effectively cancelled.
+   */
+  cancelAllPending () {
+    return this._queue.cancelAllPending()
+  }
+
+  /**
+   * @ignore
+   * @param {any} errClass ignore
+   */
+  set _cancelledErrorClass (errClass) {
+    this._queue._errorClass = errClass
+  }
+}
+
+export default Queue
+
+/**
+ * @ignore
+ */
+class _InternalQueuePriority {
+  /**
+   * @ignore
+   *
+   * @param {number} concurrency ignore
+   */
+  constructor (concurrency) {
+    this._concurrency = concurrency
+    this._iqueue = []
+    this._running = 0
+    this._errorClass = CancelledError
+  }
+
+  /**
+   * @ignore
+   * @returns {number} ignore
+   */
+  get concurrency () {
+    return this._concurrency
+  }
+
+  /**
+   * @ignore
+   * @returns {number} ignore
+   */
+  get running () {
+    return this._running
+  }
+
+  /**
+   * @ignore
+   * @returns {number} ignore
+   */
+  get pending () {
+    return this._iqueue.length - this.running
+  }
+
+  /**
+   * @ignore
+   *
+   * @param {*} fct ignored
+   * @param {*} priority ignored
+   * @returns {*} ignored
+   */
+  async exec (fct, priority) {
+    return this.execCancellable(fct, priority)[0]
+  }
+
+  /**
+   * @ignore
+   * @param {*} fct ignore
+   * @param {*} priority ignore
+   * @returns {*} ignore
+   */
+  execCancellable (fct, priority) {
+    assert(typeof fct === 'function', 'fct must be a function')
+    assert(typeof priority === 'number', 'priority must be a number')
+    const deferred = new Deferred()
+    let i = this._iqueue.length
+    while (i >= 1) {
+      const t = this._iqueue[i - 1]
+      if (t.priority >= priority) {
+        break
+      }
+      i -= 1
+    }
+    const task = {
+      asyncFct: asyncWrap(fct),
+      deferred,
+      running: false,
+      priority
+    }
+    this._iqueue.splice(i, 0, task)
+    this._checkQueue()
+    return [deferred.promise, () => {
+      if (task.running) {
+        return false
+      } else {
+        const filtered = this._iqueue.filter((v) => v !== task)
+        if (filtered.length < this._iqueue.length) {
+          this._iqueue = filtered
+          deferred.reject(new this._errorClass())
+          return true
+        } else {
+          return false
+        }
+      }
+    }]
+  }
+
+  /**
+   * @ignore
+   */
+  _checkQueue () {
+    while (true) {
+      assert(this.running >= 0, 'invalid state')
+      assert(this.running <= this.concurrency, 'invalid state')
+      if (this.running === this.concurrency) {
+        return
+      }
+      const task = this._iqueue.find((v) => !v.running)
+      if (task === undefined) {
+        return
+      }
+      task.running = true
+      this._running += 1
+      task.asyncFct().finally(() => {
+        this._running -= 1
+        this._iqueue = this._iqueue.filter((v) => v !== task)
+        this._checkQueue()
+      }).then(task.deferred.resolve, task.deferred.reject)
+    }
+  }
+
+  /**
+   * @ignore
+   * @returns {*} ignore
+   */
+  cancelAllPending () {
+    const toCancel = this._iqueue.filter((task) => !task.running)
+    this._iqueue = this._iqueue.filter((task) => task.running)
+    toCancel.forEach((task) => {
+      task.deferred.reject(new this._errorClass())
+    })
+    return toCancel.length
+  }
+}
+
+/**
+ * @ignore
+ */
+class _InternalInfinityQueue {
+  /**
+   * @ignore
+   */
+  constructor () {
+    this._running = 0
+  }
+
+  /**
+   * @ignore
+   * @returns {number} ignore
+   */
+  get concurrency () {
+    return Number.POSITIVE_INFINITY
+  }
+
+  /**
+   * @ignore
+   * @returns {number} ignore
+   */
+  get running () {
+    return this._running
+  }
+
+  /**
+   * @ignore
+   * @returns {number} ignore
+   */
+  get pending () {
+    return 0
+  }
+
+  /**
+   * @ignore
+   *
+   * @param {Function} fct ignore
+   * @returns {Promise} ignore
+   */
+  async exec (fct) {
+    return this.execCancellable(fct)[0]
+  }
+
+  /**
+   * @ignore
+   *
+   * @param {*} fct ignore
+   * @returns {*} ignore
+   */
+  execCancellable (fct) {
+    this._running += 1
+    const asyncFct = asyncWrap(fct)
+    const p = asyncFct()
+    return [p.finally(() => {
+      this._running -= 1
+    }), () => false]
+  }
+
+  /**
+   * @ignore
+   * @returns {*} ignore
+   */
+  cancelAllPending () {
+    return 0
+  }
+}
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/Scheduler.html b/docs/modern-async/1.0.4/Scheduler.html new file mode 100644 index 0000000..75916f8 --- /dev/null +++ b/docs/modern-async/1.0.4/Scheduler.html @@ -0,0 +1,1014 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Scheduler + + + + + + + + + + + + + + + + + + + +
+ +

Scheduler

+ + + + + + + +
+ + +
+ + +

+ + Scheduler + +

+ + +

A class implementing a scheduler.

+

It fills the same purpose than setInterval() but its behavior is more adapted to asynchronous +tasks. Notably it can limit the concurrency of asynchronous tasks running in parallel.

+
+ + +
+ + +
+
+ + + + +

Constructor

+ + +

+ # + new Scheduler(fct, delay, options) +

+ + + + + +
+

Constructs a Scheduler.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fct + + +function + + + + + +

The asynchronous function to call when the scheduler is triggered.

delay + + +number + + + + + +

The delay between two triggering of the scheduler, in ms.

options + + +object + + + + + + null + +

(Optional) An object that can contain additional options:

+
    +
  • startImmediate: If true a new task will be triggered as soon as the start() method is called. +Defaults to ´false`.
  • +
  • concurrency: The maximum number of concurrent tasks. See the concurrency attribute. Defaults to 1.
  • +
  • maxPending: The maximum number of pending tasks. See the maxPending attribute. Defaults to 0.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ Example + +
import { Scheduler, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  let i = 0
+  const scheduler = new Scheduler(async () => {
+    const taskNbr = i
+    i += 1
+    console.log(`Starting task ${taskNbr}`)
+    await sleep(10) // waits 10ms
+    console.log(`Ending task ${taskNbr}`)
+  }, 100) // a scheduler that triggers every 100ms
+  // the default configuration uses a maximum concurrency of 1 and doesn't allow pending
+  // tasks, which mean that if a task takes more time to complete than the delay it will be skipped
+
+  scheduler.start() // starts the scheduler
+
+  await sleep(1000) // waits 1s, during that time the task should trigger ~ 9 times
+
+  scheduler.stop() // stops the scheduler
+  console.log('Scheduler stopped')
+  // no "Starting task" console message may appear from here but you could still see a
+  // "Stopping task" as there could have a task that started before we stopped the
+  // scheduler
+})
+ +
+ + + +
+ + + + + + + + + + + + +

Members

+ + + +

+ # + concurrency :number +

+ + + + +
+

(Read-only) The maximum number of asynchronous tasks that can run in parallel.

+

This parameter only matters in the event where some tasks may take more time to execute +than the delay. If the concurrency allows it the new task will be run concurrently. If not +it may be scheduled to be executed depending on the configuration of the maxPending parameter.

+

Defaults to 1.

+
+ + + +
+ Type: +
    +
  • + +number + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + +

+ # + delay :number +

+ + + + +
+

(Read-only) The delay between two triggering of the scheduler, in milliseconds.

+
+ + + +
+ Type: +
    +
  • + +number + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + +

+ # + maxPending :number +

+ + + + +
+

(Read-only) The maximum number of tasks that can be pending.

+

In the event where one of the tasks triggered by the scheduler takes more time to execute than +the delay the next task may or may not be run concurrently depending on the configuration of +the concurrency parameter. If the maximum concurrency was already reached the new task can +be scheduled to be executed as soon as the previous task finished.

+

This parameter indicates the maximum amount of tasks that can be pending at any time. If a +task should be scheduled and the maximum amount of pending tasks is already reached +that new task will be skipped.

+

This behavior helps to prevent cases that would lead to a infinite amount of tasks to be +pending. This could happen in extreme cases where the tasks would take systematically more +time to execute than the delay.

+

Defaults to 0.

+
+ + + +
+ Type: +
    +
  • + +number + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + +

+ # + started :boolean +

+ + + + +
+

(Read-only) Whether or not the scheduler is actually started.

+
+ + + +
+ Type: +
    +
  • + +boolean + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + +

+ # + startImmediate :boolean +

+ + + + +
+

(Read-only) Whether or not a triggering of the task should occur immediately when calling start() or not.

+

Defaults to false.

+
+ + + +
+ Type: +
    +
  • + +boolean + + +
  • +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + +

+ # + start() +

+ + + + + +
+

Starts the scheduler.

+

Calling this method can trigger a task immediately depending on the configuration +of the startImmediate parameter.

+

If this method is called while the scheduler is already started it will have no effect.

+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +

+ # + stop() +

+ + + + + +
+

Stops the scheduler.

+

If, for any reason, there were pending tasks in the scheduler they will be cancelled. On the other +hand if they are still one or more tasks that are running they will continue to run until they +terminate.

+

This method is safe to call in a task if necessary.

+

If this method is called while the scheduler is already stopped it will have no effect.

+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/modern-async/1.0.4/Scheduler.mjs.html b/docs/modern-async/1.0.4/Scheduler.mjs.html new file mode 100644 index 0000000..ac1f412 --- /dev/null +++ b/docs/modern-async/1.0.4/Scheduler.mjs.html @@ -0,0 +1,373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Scheduler.mjs + + + + + + + + + + + + + + + + + + + +
+ +

Scheduler.mjs

+ + + + + + + +
+
+

+import sleepCancellable from './sleepCancellable.mjs'
+import Queue from './Queue.mjs'
+import assert from 'nanoassert'
+import asyncWrap from './asyncWrap.mjs'
+import CancelledError from './CancelledError.mjs'
+
+/**
+ * A class implementing a scheduler.
+ *
+ * It fills the same purpose than setInterval() but its behavior is more adapted to asynchronous
+ * tasks. Notably it can limit the concurrency of asynchronous tasks running in parallel.
+ *
+ * @example
+ * import { Scheduler, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   let i = 0
+ *   const scheduler = new Scheduler(async () => {
+ *     const taskNbr = i
+ *     i += 1
+ *     console.log(`Starting task ${taskNbr}`)
+ *     await sleep(10) // waits 10ms
+ *     console.log(`Ending task ${taskNbr}`)
+ *   }, 100) // a scheduler that triggers every 100ms
+ *   // the default configuration uses a maximum concurrency of 1 and doesn't allow pending
+ *   // tasks, which mean that if a task takes more time to complete than the delay it will be skipped
+ *
+ *   scheduler.start() // starts the scheduler
+ *
+ *   await sleep(1000) // waits 1s, during that time the task should trigger ~ 9 times
+ *
+ *   scheduler.stop() // stops the scheduler
+ *   console.log('Scheduler stopped')
+ *   // no "Starting task" console message may appear from here but you could still see a
+ *   // "Stopping task" as there could have a task that started before we stopped the
+ *   // scheduler
+ * })
+ */
+class Scheduler {
+  /**
+   * Constructs a Scheduler.
+   *
+   * @param {Function} fct The asynchronous function to call when the scheduler is triggered.
+   * @param {number} delay The delay between two triggering of the scheduler, in ms.
+   * @param {object} options (Optional) An object that can contain additional options:
+   *
+   *   * `startImmediate`: If true a new task will be triggered as soon as the start() method is called.
+   *     Defaults to ´false`.
+   *   * `concurrency`: The maximum number of concurrent tasks. See the `concurrency` attribute. Defaults to 1.
+   *   * `maxPending`: The maximum number of pending tasks. See the `maxPending` attribute. Defaults to 0.
+   */
+  constructor (fct, delay, options = null) {
+    options = options || {}
+    this._asyncFct = asyncWrap(fct)
+    this._delay = delay
+    assert(typeof this._delay === 'number', 'delay must be a number')
+    assert(this._delay >= 0, 'delay must be greater or equal than 0')
+    this._startImmediate = options.startImmediate || false
+    assert(typeof this._startImmediate === 'boolean',
+      'startImmediate must be a boolean')
+    this._maxPending = options.maxPending || 0
+    assert(Number.isInteger(this._maxPending) || this._maxPending === Number.POSITIVE_INFINITY,
+      'maxPending must be an integer or positive infinity')
+    assert(this._maxPending >= 0, 'maxPending must be greater or equal than 0')
+    this._queue = new Queue(options.concurrency || 1)
+    this._started = false
+    this._initialTime = null
+    this._nbrTriggering = null
+    this._cancelSleep = null
+  }
+
+  /**
+   * (Read-only) The delay between two triggering of the scheduler, in milliseconds.
+   *
+   * @member {number}
+   *
+   * @returns {number} ignore
+   */
+  get delay () {
+    return this._delay
+  }
+
+  /**
+   * (Read-only) Whether or not a triggering of the task should occur immediately when calling `start()` or not.
+   *
+   * Defaults to false.
+   *
+   * @member {boolean}
+   *
+   * @returns {boolean} ignore
+   */
+  get startImmediate () {
+    return this._startImmediate
+  }
+
+  /**
+   * (Read-only) The maximum number of asynchronous tasks that can run in parallel.
+   *
+   * This parameter only matters in the event where some tasks may take more time to execute
+   * than the delay. If the concurrency allows it the new task will be run concurrently. If not
+   * it may be scheduled to be executed depending on the configuration of the `maxPending` parameter.
+   *
+   * Defaults to 1.
+   *
+   * @member {number}
+   *
+   * @returns {number} ignore
+   */
+  get concurrency () {
+    return this._queue.concurrency
+  }
+
+  /**
+   * (Read-only) The maximum number of tasks that can be pending.
+   *
+   * In the event where one of the tasks triggered by the scheduler takes more time to execute than
+   * the delay the next task may or may not be run concurrently depending on the configuration of
+   * the `concurrency` parameter. If the maximum concurrency was already reached the new task can
+   * be scheduled to be executed as soon as the previous task finished.
+   *
+   * This parameter indicates the maximum amount of tasks that can be pending at any time. If a
+   * task should be scheduled and the maximum amount of pending tasks is already reached
+   * that new task will be skipped.
+   *
+   * This behavior helps to prevent cases that would lead to a infinite amount of tasks to be
+   * pending. This could happen in extreme cases where the tasks would take systematically more
+   * time to execute than the delay.
+   *
+   * Defaults to 0.
+   *
+   * @member {number}
+   *
+   * @returns {number} ignore
+   */
+  get maxPending () {
+    return this._maxPending
+  }
+
+  /**
+   * (Read-only) Whether or not the scheduler is actually started.
+   *
+   * @member {boolean}
+   *
+   * @returns {boolean} ignore
+   */
+  get started () {
+    return this._started
+  }
+
+  /**
+   * Starts the scheduler.
+   *
+   * Calling this method can trigger a task immediately depending on the configuration
+   * of the `startImmediate` parameter.
+   *
+   * If this method is called while the scheduler is already started it will have no effect.
+   */
+  start () {
+    if (this.started) {
+      return
+    }
+    assert(this._queue.pending === 0)
+    this._started = true
+
+    this._initialTime = new Date().getTime()
+    this._nbrTriggering = 0
+
+    if (this.startImmediate) {
+      this._triggerTask()
+    }
+
+    this._scheduleSleep()
+  }
+
+  /**
+   * Stops the scheduler.
+   *
+   * If, for any reason, there were pending tasks in the scheduler they will be cancelled. On the other
+   * hand if they are still one or more tasks that are running they will continue to run until they
+   * terminate.
+   *
+   * This method is safe to call in a task if necessary.
+   *
+   * If this method is called while the scheduler is already stopped it will have no effect.
+   */
+  stop () {
+    if (!this.started) {
+      return
+    }
+    assert(!!this._cancelSleep)
+    this._cancelSleep()
+    this._cancelSleep = null
+    this._queue.cancelAllPending()
+    assert(this._queue.pending === 0)
+    this._started = false
+    this._initialTime = null
+    this._nbrTriggering = null
+  }
+
+  /**
+   * @ignore
+   */
+  _scheduleSleep () {
+    this._nbrTriggering += 1
+    const nextTime = this._initialTime + (this.delay * this._nbrTriggering)
+    const currentTime = new Date().getTime()
+    const [promise, cancel] = sleepCancellable(nextTime - currentTime)
+    this._cancelSleep = cancel
+    promise.then(() => {
+      this._triggerTask()
+      this._scheduleSleep()
+    }, () => {
+      // ignore cancelled sleep
+    })
+  }
+
+  /**
+   * @ignore
+   */
+  _triggerTask () {
+    const reachedMaxConcurrency = this._queue.running === this._queue.concurrency
+    const forecastPending = reachedMaxConcurrency ? this._queue.pending + 1 : 0
+    if (forecastPending <= this.maxPending) {
+      this._queue.exec(this._asyncFct).catch(exceptionHandler)
+    }
+  }
+}
+
+export default Scheduler
+
+const exceptionHandler = (e) => {
+  if (e instanceof CancelledError) {
+    // ignore
+  } else {
+    throw e
+  }
+}
+
+export { exceptionHandler }
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/TimeoutError.html b/docs/modern-async/1.0.4/TimeoutError.html new file mode 100644 index 0000000..4e64464 --- /dev/null +++ b/docs/modern-async/1.0.4/TimeoutError.html @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TimeoutError + + + + + + + + + + + + + + + + + + + +
+ +

TimeoutError

+ + + + + + + +
+ + +
+ + +

+ + TimeoutError + +

+ + +

An error type which is used when an asynchronous operation takes too much time to perform.

+
+ + +
+ + +
+
+ + + + +

Constructor

+ + +

+ # + new TimeoutError(message) +

+ + + + + +
+

Constructs a new instance.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
message + + +string + + + +

The error message

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/modern-async/1.0.4/TimeoutError.mjs.html b/docs/modern-async/1.0.4/TimeoutError.mjs.html new file mode 100644 index 0000000..fd9ce08 --- /dev/null +++ b/docs/modern-async/1.0.4/TimeoutError.mjs.html @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TimeoutError.mjs + + + + + + + + + + + + + + + + + + + +
+ +

TimeoutError.mjs

+ + + + + + + +
+
+

+/**
+ * An error type which is used when an asynchronous operation takes too much time to perform.
+ */
+class TimeoutError extends Error {
+  /**
+   * Constructs a new instance.
+   *
+   * @param {string} message The error message
+   */
+  constructor (message) {
+    super(message)
+    this.name = this.constructor.name
+  }
+}
+
+export default TimeoutError
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/asyncRoot.mjs.html b/docs/modern-async/1.0.4/asyncRoot.mjs.html new file mode 100644 index 0000000..775752f --- /dev/null +++ b/docs/modern-async/1.0.4/asyncRoot.mjs.html @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + asyncRoot.mjs + + + + + + + + + + + + + + + + + + + +
+ +

asyncRoot.mjs

+ + + + + + + +
+
+

+import asyncWrap from './asyncWrap.mjs'
+
+/**
+ * Immediately calls an asynchronous function and redirects to an error handler if it throws an exception.
+ * The error handler is optional, the default one just outputs the error in the console.
+ *
+ * This function is trivial but useful in the context of node.js when you would like to use await in the root
+ * scope. It is also used in most examples provided for this library.
+ *
+ * @param {Function} fct An asynchronous function to call.
+ * @param {Function} errorHandler (Optional) A facultative error handler. This function will receive a single argument:
+ * the thrown exception. The default behavior is to output the exception in the console.
+ *
+ * @example
+ * import { asyncRoot } from 'modern-async'
+ *
+ * // or
+ *
+ * const { asyncRoot } = require('modern-async')
+ *
+ * asyncRoot(async () => {
+ *   // any code using await
+ * }, (e) => {
+ *   console.error("An error occured", e)
+ *   process.exit(-1)
+ * })
+ */
+async function asyncRoot (fct, errorHandler = null) {
+  errorHandler = errorHandler || ((e) => {
+    console.error(e)
+  })
+  const asyncFct = asyncWrap(fct)
+  try {
+    await asyncFct()
+  } catch (e) {
+    errorHandler(e)
+  }
+}
+
+export default asyncRoot
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/asyncWrap.mjs.html b/docs/modern-async/1.0.4/asyncWrap.mjs.html new file mode 100644 index 0000000..b64a78e --- /dev/null +++ b/docs/modern-async/1.0.4/asyncWrap.mjs.html @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + asyncWrap.mjs + + + + + + + + + + + + + + + + + + + +
+ +

asyncWrap.mjs

+ + + + + + + +
+
+
import assert from 'nanoassert'
+
+/**
+ * Wraps a function call that may be synchronous in a function that
+ * is guaranted to be async. This is a stricter version of calling a
+ * function and wrapping its result using `Promise.resolve()` as the new function also
+ * handles the case where the original function throws an exception.
+ *
+ * @param {Function} fct The function to wrap.
+ * @returns {Function} The wrapped function.
+ * @example
+ * import { asyncWrap } from 'modern-async'
+ *
+ * const myFunction = () => {
+ *   // any kind of function that may or may not return a promise
+ * }
+ *
+ * const asyncFct = asyncWrap(myFunction)
+ *
+ * const promise = asyncFct()
+ * console.log(promise instanceof Promise) // prints true
+ */
+function asyncWrap (fct) {
+  assert(typeof fct === 'function', 'fct must be a function')
+  return async function () {
+    return fct(...arguments)
+  }
+}
+
+export default asyncWrap
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/delay.mjs.html b/docs/modern-async/1.0.4/delay.mjs.html new file mode 100644 index 0000000..7369352 --- /dev/null +++ b/docs/modern-async/1.0.4/delay.mjs.html @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + delay.mjs + + + + + + + + + + + + + + + + + + + +
+ +

delay.mjs

+ + + + + + + +
+
+

+import delayCancellable from './delayCancellable.mjs'
+
+/**
+ * A function returning a promise that will be resolved in a later tick of the event loop.
+ *
+ * This function simply uses `setTimeout()` internally as it's the most portable solution.
+ *
+ * @returns {Promise} A promise that will be resolved on a later tick of the event loop.
+ * @example
+ * import { delay, asyncRoot } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   console.log('this executes in a tick of the event loop')
+ *   await delay()
+ *   console.log('this executes in another tick of the event loop')
+ * })
+ */
+async function delay () {
+  return delayCancellable()[0]
+}
+
+export default delay
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/delayCancellable.mjs.html b/docs/modern-async/1.0.4/delayCancellable.mjs.html new file mode 100644 index 0000000..8f02fa5 --- /dev/null +++ b/docs/modern-async/1.0.4/delayCancellable.mjs.html @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + delayCancellable.mjs + + + + + + + + + + + + + + + + + + + +
+ +

delayCancellable.mjs

+ + + + + + + +
+
+

+import sleepCancellable from './sleepCancellable.mjs'
+
+/**
+ * A function returning a promise that will be resolved in a later tick of the event loop.
+ *
+ * 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 simply uses `setTimeout()` internally as it's the most portable solution.
+ *
+ * @returns {Array} A tuple of two objects:
+ *   * The promise
+ *   * The cancel function. It will return a boolean that will be true if the promise was effectively cancelled,
+ *     false otherwise.
+ * @example
+ * import { delayCancellable, asyncRoot, CancelledError } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const [promise, cancel] = delayCancellable()
+ *   cancel()
+ *   try {
+ *     await promise
+ *   } catch (e) {
+ *     console.log(e instanceof CancelledError) // prints true
+ *   }
+ * })
+ */
+function delayCancellable () {
+  return sleepCancellable(0)
+}
+
+export default delayCancellable
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/every.mjs.html b/docs/modern-async/1.0.4/every.mjs.html new file mode 100644 index 0000000..961e1da --- /dev/null +++ b/docs/modern-async/1.0.4/every.mjs.html @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + every.mjs + + + + + + + + + + + + + + + + + + + +
+ +

every.mjs

+ + + + + + + +
+
+

+import everyLimit from './everyLimit.mjs'
+
+/**
+ * Returns `true` if all elements of an iterable pass a truth test and `false` otherwise.
+ *
+ * The iteratee will be run in parallel. If any truth test returns `false` the promise is immediately resolved.
+ *
+ * In case of exception in one of the iteratee calls the promise returned by this function will be rejected
+ * with the exception. In the very specific case where a test returns `false` and an already started task throws
+ * an exception that exception will be plainly ignored.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved to `true` if all values pass the truth test and `false`
+ * if a least one of them doesn't pass it. That promise will be rejected if one of the truth test throws
+ * an exception.
+ * @example
+ * import { every, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *
+ *   const result = await every(array, async (v) => {
+ *     // these calls will be performed in parallel
+ *     await sleep(10) // waits 10ms
+ *     return v > 0
+ *   })
+ *   console.log(result) // prints true
+ *   // total processing time should be ~ 10ms
+ * })
+ */
+async function every (iterable, iteratee) {
+  return everyLimit(iterable, iteratee, Number.POSITIVE_INFINITY)
+}
+
+export default every
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/everyLimit.mjs.html b/docs/modern-async/1.0.4/everyLimit.mjs.html new file mode 100644 index 0000000..d72460d --- /dev/null +++ b/docs/modern-async/1.0.4/everyLimit.mjs.html @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + everyLimit.mjs + + + + + + + + + + + + + + + + + + + +
+ +

everyLimit.mjs

+ + + + + + + +
+
+

+import findIndexLimit from './findIndexLimit.mjs'
+
+/**
+ * Returns `true` if all elements of an iterable pass a truth test and `false` otherwise.
+ *
+ * The iteratee will be run in parallel, up to a concurrency limit. If any truth test returns `false`
+ * the promise is immediately resolved.
+ *
+ * Whenever a test returns `false`, all the remaining tasks will be cancelled as long
+ * as they didn't started already. In case of exception in one of the iteratee calls the promise
+ * returned by this function will be rejected with the exception and the remaining pending
+ * tasks will also be cancelled. In the very specific case where a test returns `false` and an
+ * already started task throws an exception that exception will be plainly ignored.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @param {number} concurrency The number of times iteratee can be called concurrently.
+ * @returns {Promise} A promise that will be resolved to `true` if all values pass the truth test and `false`
+ * if a least one of them doesn't pass it. That promise will be rejected if one of the truth test throws
+ * an exception.
+ * @example
+ * import { everyLimit, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *
+ *   const result = await everyLimit(array, async (v) => {
+ *     // these calls will be performed in parallel with a maximum of 2
+ *     // concurrent calls
+ *     await sleep(10) // waits 10ms
+ *     return v > 0
+ *   }, 2)
+ *   console.log(result) // prints true
+ *   // total processing time should be ~ 20ms
+ * })
+ */
+async function everyLimit (iterable, iteratee, concurrency) {
+  const index = await findIndexLimit(iterable, async (value, index, iterable) => {
+    return !(await iteratee(value, index, iterable))
+  }, concurrency)
+  const result = index === -1
+  return result
+}
+
+export default everyLimit
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/everySeries.mjs.html b/docs/modern-async/1.0.4/everySeries.mjs.html new file mode 100644 index 0000000..dd11830 --- /dev/null +++ b/docs/modern-async/1.0.4/everySeries.mjs.html @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + everySeries.mjs + + + + + + + + + + + + + + + + + + + +
+ +

everySeries.mjs

+ + + + + + + +
+
+

+import everyLimit from './everyLimit.mjs'
+
+/**
+ * Returns `true` if all elements of an iterable pass a truth test and `false` otherwise.
+ *
+ * The iteratee will be run sequentially. If any truth test returns `false` the promise is
+ * immediately resolved.
+ *
+ * In case of exception in one of the iteratee calls the promise returned by this function will be
+ * rejected with the exception and the remaining pending tasks will be cancelled.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved to `true` if all values pass the truth test and `false`
+ * if a least one of them doesn't pass it. That promise will be rejected if one of the truth test throws
+ * an exception.
+ * @example
+ * import { everySeries, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *
+ *   const result = await everySeries(array, async (v) => {
+ *     // these calls will be performed sequentially
+ *     await sleep(10) // waits 10ms
+ *     return v > 0
+ *   })
+ *   console.log(result) // prints true
+ *   // total processing time should be ~ 30ms
+ * })
+ */
+async function everySeries (iterable, iteratee) {
+  return everyLimit(iterable, iteratee, 1)
+}
+
+export default everySeries
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/filter.mjs.html b/docs/modern-async/1.0.4/filter.mjs.html new file mode 100644 index 0000000..a39da7f --- /dev/null +++ b/docs/modern-async/1.0.4/filter.mjs.html @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + filter.mjs + + + + + + + + + + + + + + + + + + + +
+ +

filter.mjs

+ + + + + + + +
+
+

+import filterLimit from './filterLimit.mjs'
+
+/**
+ * Returns a new array of all the values in iterable which pass an asynchronous truth test.
+ *
+ * The calls to `iteratee` will perform in parallel, but the results array will be in the same order
+ * than the original.
+ *
+ * If any of the calls to iteratee throws an exception the returned promise will be rejected.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of `iterable`. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved with an array containing all the values that passed
+ * the truth test. This promise will be rejected if any of the `iteratee` calls throws an exception.
+ * @example
+ * import { filter, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await filter(array, async (v) => {
+ *     // these calls will be performed in parallel
+ *     await sleep(10) // waits 10ms
+ *     return v % 2 === 1
+ *   })
+ *   console.log(result) // prints [1, 3]
+ *   // total processing time should be ~ 10ms
+ * })
+ */
+async function filter (iterable, iteratee) {
+  return filterLimit(iterable, iteratee, Number.POSITIVE_INFINITY)
+}
+
+export default filter
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/filterLimit.mjs.html b/docs/modern-async/1.0.4/filterLimit.mjs.html new file mode 100644 index 0000000..c75b6d7 --- /dev/null +++ b/docs/modern-async/1.0.4/filterLimit.mjs.html @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + filterLimit.mjs + + + + + + + + + + + + + + + + + + + +
+ +

filterLimit.mjs

+ + + + + + + +
+
+

+import mapLimit from './mapLimit.mjs'
+import assert from 'nanoassert'
+
+/**
+ * Returns a new array of all the values in iterable which pass an asynchronous truth test.
+ *
+ * The calls to `iteratee` will perform in parallel, up to the concurrency limit, but the results array will be
+ * in the same order than the original.
+ *
+ * If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining
+ * pending tasks will be cancelled.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of `iterable`. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @param {number} concurrency The number of times iteratee can be called concurrently.
+ * @returns {Promise} A promise that will be resolved with an array containing all the values that passed
+ * the truth test. This promise will be rejected if any of the `iteratee` calls throws an exception.
+ * @example
+ * import { filterLimit, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await filterLimit(array, async (v) => {
+ *     // these calls will be performed in parallel with a maximum of 2
+ *     // concurrent calls
+ *     await sleep(10) // waits 10ms
+ *     return v % 2 === 1
+ *   }, 2)
+ *   console.log(result) // prints [1, 3]
+ *   // total processing time should be ~ 20ms
+ * })
+ */
+async function filterLimit (iterable, iteratee, concurrency) {
+  assert(typeof iteratee === 'function', 'iteratee must be a function')
+  return (await mapLimit(iterable, async (v, i, t) => {
+    return [v, await iteratee(v, i, t)]
+  }, concurrency)).filter(([v, t]) => t).map(([v, t]) => v)
+}
+
+export default filterLimit
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/filterSeries.mjs.html b/docs/modern-async/1.0.4/filterSeries.mjs.html new file mode 100644 index 0000000..d37f6d2 --- /dev/null +++ b/docs/modern-async/1.0.4/filterSeries.mjs.html @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + filterSeries.mjs + + + + + + + + + + + + + + + + + + + +
+ +

filterSeries.mjs

+ + + + + + + +
+
+

+import filterLimit from './filterLimit.mjs'
+
+/**
+ * Returns a new array of all the values in iterable which pass an asynchronous truth test.
+ *
+ * The calls to `iteratee` will perform sequentially and the results array will be in the same order
+ * than the original.
+ *
+ * If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining
+ * pending tasks will be cancelled.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved with an array containing all the values that passed
+ * the truth test. This promise will be rejected if any of the `iteratee` calls throws an exception.
+ * @example
+ * import { filterSeries, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await filterSeries(array, async (v) => {
+ *     // these calls will be performed sequentially
+ *     await sleep(10) // waits 10ms
+ *     return v % 2 === 1
+ *   })
+ *   console.log(result) // prints [1, 3]
+ *   // total processing time should be ~ 30ms
+ * })
+ */
+async function filterSeries (iterable, iteratee) {
+  return filterLimit(iterable, iteratee, 1)
+}
+
+export default filterSeries
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/find.mjs.html b/docs/modern-async/1.0.4/find.mjs.html new file mode 100644 index 0000000..732916c --- /dev/null +++ b/docs/modern-async/1.0.4/find.mjs.html @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + find.mjs + + + + + + + + + + + + + + + + + + + +
+ +

find.mjs

+ + + + + + + +
+
+

+import findLimit from './findLimit.mjs'
+
+/**
+ * Returns the first element of an iterable that passes an asynchronous truth test.
+ *
+ * The calls to `iteratee` will run in parallel. This implies that the element found by this function may not
+ * be the first element of the iterable able to pass the truth test. It will be the first one in time
+ * for which one of the parallel calls to `iteratee` was able to return a positive result. If you need
+ * a sequential alternative use `findSeries()`.
+ *
+ * In case of exception in one of the `iteratee` calls the promise returned by this function will be
+ * rejected with the exception. In the very specific case where a result is found and an
+ * already started task throws an exception that exception will be plainly ignored.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved with the first found value or rejected if one of the
+ * `iteratee` calls throws an exception before finding a value. If no value is found it will return `undefined`.
+ * @example
+ * import { find, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await find(array, async (v) => {
+ *     // these calls will be performed in parallel
+ *     await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+ *     return v % 2 === 1
+ *   })
+ *   console.log(result) // prints 1 or 3 randomly
+ * })
+ */
+async function find (iterable, iteratee) {
+  return findLimit(iterable, iteratee, Number.POSITIVE_INFINITY)
+}
+
+export default find
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/findIndex.mjs.html b/docs/modern-async/1.0.4/findIndex.mjs.html new file mode 100644 index 0000000..213bc7e --- /dev/null +++ b/docs/modern-async/1.0.4/findIndex.mjs.html @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + findIndex.mjs + + + + + + + + + + + + + + + + + + + +
+ +

findIndex.mjs

+ + + + + + + +
+
+

+import findIndexLimit from './findIndexLimit.mjs'
+
+/**
+ * Returns the index of the first element of an iterable that passes an asynchronous truth test.
+ *
+ * The calls to `iteratee` will run in parallel. This implies that the element found by this function may not
+ * be the first element of the iterable able to pass the truth test. It will be the first one in time
+ * for which one of the parallel calls to `iteratee` was able to return a positive result. If you need
+ * a sequential alternative use `findIndexSeries()`.
+ *
+ * In case of exception in one of the `iteratee` calls the promise returned by this function will be
+ * rejected with the exception. In the very specific case where a result is found and an
+ * already started task throws an exception that exception will be plainly ignored.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved with the index of the first found value or rejected if one of the
+ * `iteratee` calls throws an exception before finding a value. If no value is found it will return `-1`.
+ * @example
+ * import { findIndex, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await findIndex(array, async (v) => {
+ *     // these calls will be performed in parallel
+ *     await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+ *     return v % 2 === 1
+ *   })
+ *   console.log(result) // prints 0 or 2 randomly
+ * })
+ */
+async function findIndex (iterable, iteratee) {
+  return findIndexLimit(iterable, iteratee, Number.POSITIVE_INFINITY)
+}
+
+export default findIndex
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/findIndexLimit.mjs.html b/docs/modern-async/1.0.4/findIndexLimit.mjs.html new file mode 100644 index 0000000..5b5cc99 --- /dev/null +++ b/docs/modern-async/1.0.4/findIndexLimit.mjs.html @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + findIndexLimit.mjs + + + + + + + + + + + + + + + + + + + +
+ +

findIndexLimit.mjs

+ + + + + + + +
+
+

+import Queue from './Queue.mjs'
+import assert from 'nanoassert'
+import CancelledError from './CancelledError.mjs'
+
+/**
+ * Returns the index of the first element of an iterable that passes an asynchronous truth test.
+ *
+ * The calls to `iteratee` will run in parallel, up to a concurrency limit. This implies that
+ * the element found by this function may not be the first element of the iterable able to pass the
+ * truth test. It will be the first one in time for which one of the parallel calls to `iteratee` was able to
+ * return a positive result. If you need a sequential alternative use `findIndexSeries()`.
+ *
+ * Whenever a result is found, all the remaining tasks will be cancelled as long
+ * as they didn't started already. In case of exception in one of the iteratee calls the promise
+ * returned by this function will be rejected with the exception and the remaining pending
+ * tasks will also be cancelled. In the very specific case where a result is found and an
+ * already started task throws an exception that exception will be plainly ignored.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @param {number} concurrency The number of times iteratee can be called concurrently.
+ * @returns {Promise} A promise that will be resolved with the index of the first found value or rejected if one of the
+ * `iteratee` calls throws an exception before finding a value. If no value is found it will return `-1`.
+ * @example
+ * import { findIndexLimit, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3, 4, 5]
+ *   const result = await findIndexLimit(array, async (v) => {
+ *     // these calls will be performed in parallel with a maximum of 3
+ *     // concurrent calls
+ *     await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+ *     return v % 2 === 1
+ *   }, 3)
+ *   console.log(result) // prints 0, 2 or 4 randomly
+ *   // 4 is a potential result in this case even with a concurrency of 3 due to how
+ *   // randomness works, and all asynchronous operations are inherently random. The only way to ensure an
+ *   // order is to use a concurreny of 1 or to use findSeries() which does the same thing.
+ * })
+ */
+async function findIndexLimit (iterable, iteratee, concurrency) {
+  assert(typeof iteratee === 'function', 'iteratee must be a function')
+  const queue = new Queue(concurrency)
+  queue._cancelledErrorClass = CustomCancelledError
+  const promises = []
+  let current = promises
+  let finalized = false
+  const finalize = () => {
+    if (!finalized) {
+      current.forEach((p) => {
+        p.catch(() => {
+          // ignore the exception
+        })
+      })
+      queue.cancelAllPending()
+    }
+    finalized = true
+  }
+  let i = 0
+  for (const el of iterable) {
+    const index = i
+    promises.push((async () => {
+      try {
+        const gres = await queue.exec(async () => {
+          try {
+            const res = await iteratee(el, index, iterable)
+            if (res) {
+              finalize()
+            }
+            return res
+          } catch (e) {
+            finalize()
+            throw e
+          }
+        })
+        return [index, 'resolved', gres]
+      } catch (e) {
+        return [index, 'rejected', e]
+      }
+    })())
+    i += 1
+  }
+
+  try {
+    while (current.length > 0) {
+      const [index, state, result] = await Promise.race(current)
+      if (state === 'resolved') {
+        if (result) {
+          return index
+        }
+      } else { // error
+        if (!(result instanceof CustomCancelledError)) {
+          throw result
+        }
+      }
+      promises[index] = null
+      current = promises.filter((p) => p !== null)
+    }
+    return -1
+  } finally {
+    finalize()
+  }
+}
+
+/**
+ * @ignore
+ */
+class CustomCancelledError extends CancelledError {}
+
+export default findIndexLimit
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/findIndexSeries.mjs.html b/docs/modern-async/1.0.4/findIndexSeries.mjs.html new file mode 100644 index 0000000..8ef0336 --- /dev/null +++ b/docs/modern-async/1.0.4/findIndexSeries.mjs.html @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + findIndexSeries.mjs + + + + + + + + + + + + + + + + + + + +
+ +

findIndexSeries.mjs

+ + + + + + + +
+
+

+import findIndexLimit from './findIndexLimit.mjs'
+
+/**
+ * Returns the index of the first element of an iterable that passes an asynchronous truth test.
+ *
+ * The calls to `iteratee` will run sequentially. As opposed to `findIndex()` and `findIndexLimit()` this ensures
+ * that if multiple values may pass the truth test it will be the first one of the iterable that will be
+ * returned.
+ *
+ * In case of exception in one of the `iteratee` calls the promise returned by this function will be
+ * rejected with the exception and the remaining pending tasks will be cancelled.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved with the index of the first found value or rejected if one of the
+ * `iteratee` calls throws an exception before finding a value. If no value is found it will return `-1`.
+ * @example
+ * import { findIndexSeries, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await findIndexSeries(array, async (v) => {
+ *     // these calls will be performed sequentially
+ *     await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+ *     return v % 2 === 1
+ *   })
+ *   console.log(result) // always prints 0
+ * })
+ */
+async function findIndexSeries (iterable, iteratee) {
+  return findIndexLimit(iterable, iteratee, 1)
+}
+
+export default findIndexSeries
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/findLimit.mjs.html b/docs/modern-async/1.0.4/findLimit.mjs.html new file mode 100644 index 0000000..a108555 --- /dev/null +++ b/docs/modern-async/1.0.4/findLimit.mjs.html @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + findLimit.mjs + + + + + + + + + + + + + + + + + + + +
+ +

findLimit.mjs

+ + + + + + + +
+
+

+import findIndexLimit from './findIndexLimit.mjs'
+
+/**
+ * Returns the first element of an iterable that passes an asynchronous truth test.
+ *
+ * The calls to `iteratee` will run in parallel, up to a concurrency limit. This implies that
+ * the element found by this function may not be the first element of the iterable able to pass the
+ * truth test. It will be the first one for which one of the parallel calls to `iteratee` was able to
+ * return a positive result. If you need a sequential alternative use `findSeries()`.
+ *
+ * Whenever a result is found, all the remaining tasks will be cancelled as long
+ * as they didn't started already. In case of exception in one of the `iteratee` calls the promise
+ * returned by this function will be rejected with the exception and the remaining pending
+ * tasks will also be cancelled. In the very specific case where a result is found and an
+ * already started task throws an exception that exception will be plainly ignored.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @param {number} concurrency The number of times iteratee can be called concurrently.
+ * @returns {Promise} A promise that will be resolved with the first found value or rejected if one of the
+ * `iteratee` calls throws an exception before finding a value. If no value is found it will return `undefined`.
+ * @example
+ * import { findLimit, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3, 4, 5]
+ *   const result = await findLimit(array, async (v) => {
+ *     // these calls will be performed in parallel with a maximum of 3
+ *     // concurrent calls
+ *     await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+ *     return v % 2 === 1
+ *   }, 3)
+ *   console.log(result) // prints 1, 3 or 5 randomly
+ *   // 5 is a potential result in this case even with a concurrency of 3 due to how
+ *   // randomness works, and all asynchronous operations are inherently random. The only way to ensure an
+ *   // order is to use a concurreny of 1 or to use findSeries() which does the same thing.
+ * })
+ */
+async function findLimit (iterable, iteratee, concurrency) {
+  const arr = Array.from(iterable)
+  const index = await findIndexLimit(iterable, iteratee, concurrency)
+  return index === -1 ? undefined : arr[index]
+}
+
+export default findLimit
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/findSeries.mjs.html b/docs/modern-async/1.0.4/findSeries.mjs.html new file mode 100644 index 0000000..4a5ef59 --- /dev/null +++ b/docs/modern-async/1.0.4/findSeries.mjs.html @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + findSeries.mjs + + + + + + + + + + + + + + + + + + + +
+ +

findSeries.mjs

+ + + + + + + +
+
+

+import findLimit from './findLimit.mjs'
+
+/**
+ * Returns the first element of an iterable that passes an asynchronous truth test.
+ *
+ * The calls to `iteratee` will run sequentially. As opposed to `find()` and `findLimit()` this ensures
+ * that if multiple values may pass the truth test it will be the first one of the iterable that will be
+ * returned.
+ *
+ * In case of exception in one of the `iteratee` calls the promise returned by this function will be
+ * rejected with the exception.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved with the first found value or rejected if one of the
+ * `iteratee` calls throws an exception before finding a value. If no value is found it will return `undefined`.
+ * @example
+ * import { findSeries, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await findSeries(array, async (v) => {
+ *     // these calls will be performed sequentially
+ *     await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+ *     return v % 2 === 1
+ *   })
+ *   console.log(result) // always prints 1
+ * })
+ */
+async function findSeries (iterable, iteratee) {
+  return findLimit(iterable, iteratee, 1)
+}
+
+export default findSeries
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/fonts/MavenPro-Regular.ttf b/docs/modern-async/1.0.4/fonts/MavenPro-Regular.ttf new file mode 100644 index 0000000..1dfff0e Binary files /dev/null and b/docs/modern-async/1.0.4/fonts/MavenPro-Regular.ttf differ diff --git a/docs/modern-async/1.0.4/fonts/Montserrat-Regular.ttf b/docs/modern-async/1.0.4/fonts/Montserrat-Regular.ttf new file mode 100755 index 0000000..8d443d5 Binary files /dev/null and b/docs/modern-async/1.0.4/fonts/Montserrat-Regular.ttf differ diff --git a/docs/modern-async/1.0.4/fonts/Muli-Black.ttf b/docs/modern-async/1.0.4/fonts/Muli-Black.ttf new file mode 100644 index 0000000..0aa7547 Binary files /dev/null and b/docs/modern-async/1.0.4/fonts/Muli-Black.ttf differ diff --git a/docs/modern-async/1.0.4/fonts/OFL-hind.txt b/docs/modern-async/1.0.4/fonts/OFL-hind.txt new file mode 100755 index 0000000..79115a5 --- /dev/null +++ b/docs/modern-async/1.0.4/fonts/OFL-hind.txt @@ -0,0 +1,93 @@ +Copyright (c) 2014, Indian Type Foundry (info@indiantypefoundry.com). + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/modern-async/1.0.4/fonts/OFL-montserrat.txt b/docs/modern-async/1.0.4/fonts/OFL-montserrat.txt new file mode 100755 index 0000000..7881887 --- /dev/null +++ b/docs/modern-async/1.0.4/fonts/OFL-montserrat.txt @@ -0,0 +1,93 @@ +Copyright 2011 The Montserrat Project Authors (https://github.com/JulietaUla/Montserrat) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/modern-async/1.0.4/forEach.mjs.html b/docs/modern-async/1.0.4/forEach.mjs.html new file mode 100644 index 0000000..b7084fe --- /dev/null +++ b/docs/modern-async/1.0.4/forEach.mjs.html @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + forEach.mjs + + + + + + + + + + + + + + + + + + + +
+ +

forEach.mjs

+ + + + + + + +
+
+

+import forEachLimit from './forEachLimit.mjs'
+
+/**
+ * Calls a function on each element of iterable.
+ *
+ * Multiple calls to `iteratee` will be performed in parallel.
+ *
+ * If any of the calls to iteratee throws an exception the returned promise will be rejected.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved when all the calls to `iteratee` have been done.
+ * This promise will be rejected if any call to `iteratee` throws an exception.
+ * @example
+ * import { forEach, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   await forEach(array, async (v) => {
+ *     // these calls will be performed in parallel
+ *     await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+ *     console.log(v)
+ *   })
+ *   // prints 1, 2 and 3 in a random order
+ * })
+ */
+async function forEach (iterable, iteratee) {
+  return forEachLimit(iterable, iteratee, Number.POSITIVE_INFINITY)
+}
+
+export default forEach
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/forEachLimit.mjs.html b/docs/modern-async/1.0.4/forEachLimit.mjs.html new file mode 100644 index 0000000..17c65a5 --- /dev/null +++ b/docs/modern-async/1.0.4/forEachLimit.mjs.html @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + forEachLimit.mjs + + + + + + + + + + + + + + + + + + + +
+ +

forEachLimit.mjs

+ + + + + + + +
+
+

+import mapLimit from './mapLimit.mjs'
+
+/**
+ * Calls a function on each element of iterable.
+ *
+ * Multiple calls to `iteratee` will be performed in parallel, up to the concurrency limit.
+ *
+ * If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining
+ * pending tasks will be cancelled.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @param {number} concurrency The number of times iteratee can be called concurrently.
+ * @returns {Promise} A promise that will be resolved when all the calls to `iteratee` have been done.
+ * This promise will be rejected if any call to `iteratee` throws an exception.
+ * @example
+ * import { forEachLimit, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   await forEachLimit(array, async (v) => {
+ *     // these calls will be performed in parallel with a maximum of 2
+ *     // concurrent calls
+ *     await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+ *     console.log(v)
+ *   }, 2)
+ *   // prints 1, 2 and 3 in a random order (it will always print 1 or 2 before printing 3 due to
+ *   // the concurrency limit and the internal scheduling order)
+ * })
+ */
+async function forEachLimit (iterable, iteratee, concurrency) {
+  await mapLimit(iterable, async (v, i, t) => {
+    await iteratee(v, i, t)
+  }, concurrency)
+}
+
+export default forEachLimit
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/forEachSeries.mjs.html b/docs/modern-async/1.0.4/forEachSeries.mjs.html new file mode 100644 index 0000000..5e0cc4d --- /dev/null +++ b/docs/modern-async/1.0.4/forEachSeries.mjs.html @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + forEachSeries.mjs + + + + + + + + + + + + + + + + + + + +
+ +

forEachSeries.mjs

+ + + + + + + +
+
+

+import forEachLimit from './forEachLimit.mjs'
+
+/**
+ * Calls a function on each element of iterable.
+ *
+ * Multiple calls to `iteratee` will be performed sequentially.
+ *
+ * If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining
+ * pending tasks will be cancelled.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved when all the calls to `iteratee` have been done.
+ * This promise will be rejected if any call to `iteratee` throws an exception.
+ * @example
+ * import { forEachSeries, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   await forEachSeries(array, async (v) => {
+ *     // these calls will be performed sequentially
+ *     await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+ *     console.log(v)
+ *   })
+ *   // prints 1, 2 and 3 in that exact order
+ * })
+ */
+async function forEachSeries (iterable, iteratee) {
+  return forEachLimit(iterable, iteratee, 1)
+}
+
+export default forEachSeries
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/global.html b/docs/modern-async/1.0.4/global.html new file mode 100644 index 0000000..e88797b --- /dev/null +++ b/docs/modern-async/1.0.4/global.html @@ -0,0 +1,7141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Global + + + + + + + + + + + + + + + + + + + +
+ +

Global

+ + + + + + + +
+ + + +
+
+ + + + + + +
+ + + + + + + + + + + + + + +

Methods

+ + + + + + +

+ # + (async) asyncRoot(fct, errorHandler) +

+ + + + + +
+

Immediately calls an asynchronous function and redirects to an error handler if it throws an exception. +The error handler is optional, the default one just outputs the error in the console.

+

This function is trivial but useful in the context of node.js when you would like to use await in the root +scope. It is also used in most examples provided for this library.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fct + + +function + + + + + +

An asynchronous function to call.

errorHandler + + +function + + + + + + null + +

(Optional) A facultative error handler. This function will receive a single argument: +the thrown exception. The default behavior is to output the exception in the console.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
+ Example + +
import { asyncRoot } from 'modern-async'
+
+// or
+
+const { asyncRoot } = require('modern-async')
+
+asyncRoot(async () => {
+  // any code using await
+}, (e) => {
+  console.error("An error occured", e)
+  process.exit(-1)
+})
+ +
+ + + + + + + +

+ # + asyncWrap(fct) → {function} +

+ + + + + +
+

Wraps a function call that may be synchronous in a function that +is guaranted to be async. This is a stricter version of calling a +function and wrapping its result using Promise.resolve() as the new function also +handles the case where the original function throws an exception.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fct + + +function + + + +

The function to wrap.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

The wrapped function.

+
+ + + +
+
+ Type +
+
+ +function + + +
+
+ +
+ + + +
+ Example + +
import { asyncWrap } from 'modern-async'
+
+const myFunction = () => {
+  // any kind of function that may or may not return a promise
+}
+
+const asyncFct = asyncWrap(myFunction)
+
+const promise = asyncFct()
+console.log(promise instanceof Promise) // prints true
+ +
+ + + + + + + +

+ # + (async) delay() → {Promise} +

+ + + + + +
+

A function returning a promise that will be resolved in a later tick of the event loop.

+

This function simply uses setTimeout() internally as it's the most portable solution.

+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved on a later tick of the event loop.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { delay, asyncRoot } from 'modern-async'
+
+asyncRoot(async () => {
+  console.log('this executes in a tick of the event loop')
+  await delay()
+  console.log('this executes in another tick of the event loop')
+})
+ +
+ + + + + + + +

+ # + delayCancellable() → {Array} +

+ + + + + +
+

A function returning a promise that will be resolved in a later tick of the event loop.

+

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 simply uses setTimeout() internally as it's the most portable solution.

+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A tuple of two objects:

+
    +
  • The promise
  • +
  • The cancel function. It will return a boolean that will be true if the promise was effectively cancelled, +false otherwise.
  • +
+
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ +
+ + + +
+ Example + +
import { delayCancellable, asyncRoot, CancelledError } from 'modern-async'
+
+asyncRoot(async () => {
+  const [promise, cancel] = delayCancellable()
+  cancel()
+  try {
+    await promise
+  } catch (e) {
+    console.log(e instanceof CancelledError) // prints true
+  }
+})
+ +
+ + + + + + + +

+ # + (async) every(iterable, iteratee) → {Promise} +

+ + + + + +
+

Returns true if all elements of an iterable pass a truth test and false otherwise.

+

The iteratee will be run in parallel. If any truth test returns false the promise is immediately resolved.

+

In case of exception in one of the iteratee calls the promise returned by this function will be rejected +with the exception. In the very specific case where a test returns false and an already started task throws +an exception that exception will be plainly ignored.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved to true if all values pass the truth test and false +if a least one of them doesn't pass it. That promise will be rejected if one of the truth test throws +an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { every, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+
+  const result = await every(array, async (v) => {
+    // these calls will be performed in parallel
+    await sleep(10) // waits 10ms
+    return v > 0
+  })
+  console.log(result) // prints true
+  // total processing time should be ~ 10ms
+})
+ +
+ + + + + + + +

+ # + (async) everyLimit(iterable, iteratee, concurrency) → {Promise} +

+ + + + + +
+

Returns true if all elements of an iterable pass a truth test and false otherwise.

+

The iteratee will be run in parallel, up to a concurrency limit. If any truth test returns false +the promise is immediately resolved.

+

Whenever a test returns false, all the remaining tasks will be cancelled as long +as they didn't started already. In case of exception in one of the iteratee calls the promise +returned by this function will be rejected with the exception and the remaining pending +tasks will also be cancelled. In the very specific case where a test returns false and an +already started task throws an exception that exception will be plainly ignored.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
concurrency + + +number + + + +

The number of times iteratee can be called concurrently.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved to true if all values pass the truth test and false +if a least one of them doesn't pass it. That promise will be rejected if one of the truth test throws +an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { everyLimit, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+
+  const result = await everyLimit(array, async (v) => {
+    // these calls will be performed in parallel with a maximum of 2
+    // concurrent calls
+    await sleep(10) // waits 10ms
+    return v > 0
+  }, 2)
+  console.log(result) // prints true
+  // total processing time should be ~ 20ms
+})
+ +
+ + + + + + + +

+ # + (async) everySeries(iterable, iteratee) → {Promise} +

+ + + + + +
+

Returns true if all elements of an iterable pass a truth test and false otherwise.

+

The iteratee will be run sequentially. If any truth test returns false the promise is +immediately resolved.

+

In case of exception in one of the iteratee calls the promise returned by this function will be +rejected with the exception and the remaining pending tasks will be cancelled.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved to true if all values pass the truth test and false +if a least one of them doesn't pass it. That promise will be rejected if one of the truth test throws +an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { everySeries, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+
+  const result = await everySeries(array, async (v) => {
+    // these calls will be performed sequentially
+    await sleep(10) // waits 10ms
+    return v > 0
+  })
+  console.log(result) // prints true
+  // total processing time should be ~ 30ms
+})
+ +
+ + + + + + + +

+ # + (async) filter(iterable, iteratee) → {Promise} +

+ + + + + +
+

Returns a new array of all the values in iterable which pass an asynchronous truth test.

+

The calls to iteratee will perform in parallel, but the results array will be in the same order +than the original.

+

If any of the calls to iteratee throws an exception the returned promise will be rejected.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with an array containing all the values that passed +the truth test. This promise will be rejected if any of the iteratee calls throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { filter, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await filter(array, async (v) => {
+    // these calls will be performed in parallel
+    await sleep(10) // waits 10ms
+    return v % 2 === 1
+  })
+  console.log(result) // prints [1, 3]
+  // total processing time should be ~ 10ms
+})
+ +
+ + + + + + + +

+ # + (async) filterLimit(iterable, iteratee, concurrency) → {Promise} +

+ + + + + +
+

Returns a new array of all the values in iterable which pass an asynchronous truth test.

+

The calls to iteratee will perform in parallel, up to the concurrency limit, but the results array will be +in the same order than the original.

+

If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining +pending tasks will be cancelled.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
concurrency + + +number + + + +

The number of times iteratee can be called concurrently.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with an array containing all the values that passed +the truth test. This promise will be rejected if any of the iteratee calls throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { filterLimit, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await filterLimit(array, async (v) => {
+    // these calls will be performed in parallel with a maximum of 2
+    // concurrent calls
+    await sleep(10) // waits 10ms
+    return v % 2 === 1
+  }, 2)
+  console.log(result) // prints [1, 3]
+  // total processing time should be ~ 20ms
+})
+ +
+ + + + + + + +

+ # + (async) filterSeries(iterable, iteratee) → {Promise} +

+ + + + + +
+

Returns a new array of all the values in iterable which pass an asynchronous truth test.

+

The calls to iteratee will perform sequentially and the results array will be in the same order +than the original.

+

If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining +pending tasks will be cancelled.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with an array containing all the values that passed +the truth test. This promise will be rejected if any of the iteratee calls throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { filterSeries, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await filterSeries(array, async (v) => {
+    // these calls will be performed sequentially
+    await sleep(10) // waits 10ms
+    return v % 2 === 1
+  })
+  console.log(result) // prints [1, 3]
+  // total processing time should be ~ 30ms
+})
+ +
+ + + + + + + +

+ # + (async) find(iterable, iteratee) → {Promise} +

+ + + + + +
+

Returns the first element of an iterable that passes an asynchronous truth test.

+

The calls to iteratee will run in parallel. This implies that the element found by this function may not +be the first element of the iterable able to pass the truth test. It will be the first one in time +for which one of the parallel calls to iteratee was able to return a positive result. If you need +a sequential alternative use findSeries().

+

In case of exception in one of the iteratee calls the promise returned by this function will be +rejected with the exception. In the very specific case where a result is found and an +already started task throws an exception that exception will be plainly ignored.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with the first found value or rejected if one of the +iteratee calls throws an exception before finding a value. If no value is found it will return undefined.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { find, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await find(array, async (v) => {
+    // these calls will be performed in parallel
+    await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+    return v % 2 === 1
+  })
+  console.log(result) // prints 1 or 3 randomly
+})
+ +
+ + + + + + + +

+ # + (async) findIndex(iterable, iteratee) → {Promise} +

+ + + + + +
+

Returns the index of the first element of an iterable that passes an asynchronous truth test.

+

The calls to iteratee will run in parallel. This implies that the element found by this function may not +be the first element of the iterable able to pass the truth test. It will be the first one in time +for which one of the parallel calls to iteratee was able to return a positive result. If you need +a sequential alternative use findIndexSeries().

+

In case of exception in one of the iteratee calls the promise returned by this function will be +rejected with the exception. In the very specific case where a result is found and an +already started task throws an exception that exception will be plainly ignored.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with the index of the first found value or rejected if one of the +iteratee calls throws an exception before finding a value. If no value is found it will return -1.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { findIndex, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await findIndex(array, async (v) => {
+    // these calls will be performed in parallel
+    await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+    return v % 2 === 1
+  })
+  console.log(result) // prints 0 or 2 randomly
+})
+ +
+ + + + + + + +

+ # + (async) findIndexLimit(iterable, iteratee, concurrency) → {Promise} +

+ + + + + +
+

Returns the index of the first element of an iterable that passes an asynchronous truth test.

+

The calls to iteratee will run in parallel, up to a concurrency limit. This implies that +the element found by this function may not be the first element of the iterable able to pass the +truth test. It will be the first one in time for which one of the parallel calls to iteratee was able to +return a positive result. If you need a sequential alternative use findIndexSeries().

+

Whenever a result is found, all the remaining tasks will be cancelled as long +as they didn't started already. In case of exception in one of the iteratee calls the promise +returned by this function will be rejected with the exception and the remaining pending +tasks will also be cancelled. In the very specific case where a result is found and an +already started task throws an exception that exception will be plainly ignored.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
concurrency + + +number + + + +

The number of times iteratee can be called concurrently.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with the index of the first found value or rejected if one of the +iteratee calls throws an exception before finding a value. If no value is found it will return -1.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { findIndexLimit, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3, 4, 5]
+  const result = await findIndexLimit(array, async (v) => {
+    // these calls will be performed in parallel with a maximum of 3
+    // concurrent calls
+    await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+    return v % 2 === 1
+  }, 3)
+  console.log(result) // prints 0, 2 or 4 randomly
+  // 4 is a potential result in this case even with a concurrency of 3 due to how
+  // randomness works, and all asynchronous operations are inherently random. The only way to ensure an
+  // order is to use a concurreny of 1 or to use findSeries() which does the same thing.
+})
+ +
+ + + + + + + +

+ # + (async) findIndexSeries(iterable, iteratee) → {Promise} +

+ + + + + +
+

Returns the index of the first element of an iterable that passes an asynchronous truth test.

+

The calls to iteratee will run sequentially. As opposed to findIndex() and findIndexLimit() this ensures +that if multiple values may pass the truth test it will be the first one of the iterable that will be +returned.

+

In case of exception in one of the iteratee calls the promise returned by this function will be +rejected with the exception and the remaining pending tasks will be cancelled.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with the index of the first found value or rejected if one of the +iteratee calls throws an exception before finding a value. If no value is found it will return -1.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { findIndexSeries, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await findIndexSeries(array, async (v) => {
+    // these calls will be performed sequentially
+    await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+    return v % 2 === 1
+  })
+  console.log(result) // always prints 0
+})
+ +
+ + + + + + + +

+ # + (async) findLimit(iterable, iteratee, concurrency) → {Promise} +

+ + + + + +
+

Returns the first element of an iterable that passes an asynchronous truth test.

+

The calls to iteratee will run in parallel, up to a concurrency limit. This implies that +the element found by this function may not be the first element of the iterable able to pass the +truth test. It will be the first one for which one of the parallel calls to iteratee was able to +return a positive result. If you need a sequential alternative use findSeries().

+

Whenever a result is found, all the remaining tasks will be cancelled as long +as they didn't started already. In case of exception in one of the iteratee calls the promise +returned by this function will be rejected with the exception and the remaining pending +tasks will also be cancelled. In the very specific case where a result is found and an +already started task throws an exception that exception will be plainly ignored.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
concurrency + + +number + + + +

The number of times iteratee can be called concurrently.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with the first found value or rejected if one of the +iteratee calls throws an exception before finding a value. If no value is found it will return undefined.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { findLimit, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3, 4, 5]
+  const result = await findLimit(array, async (v) => {
+    // these calls will be performed in parallel with a maximum of 3
+    // concurrent calls
+    await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+    return v % 2 === 1
+  }, 3)
+  console.log(result) // prints 1, 3 or 5 randomly
+  // 5 is a potential result in this case even with a concurrency of 3 due to how
+  // randomness works, and all asynchronous operations are inherently random. The only way to ensure an
+  // order is to use a concurreny of 1 or to use findSeries() which does the same thing.
+})
+ +
+ + + + + + + +

+ # + (async) findSeries(iterable, iteratee) → {Promise} +

+ + + + + +
+

Returns the first element of an iterable that passes an asynchronous truth test.

+

The calls to iteratee will run sequentially. As opposed to find() and findLimit() this ensures +that if multiple values may pass the truth test it will be the first one of the iterable that will be +returned.

+

In case of exception in one of the iteratee calls the promise returned by this function will be +rejected with the exception.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with the first found value or rejected if one of the +iteratee calls throws an exception before finding a value. If no value is found it will return undefined.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { findSeries, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await findSeries(array, async (v) => {
+    // these calls will be performed sequentially
+    await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+    return v % 2 === 1
+  })
+  console.log(result) // always prints 1
+})
+ +
+ + + + + + + +

+ # + (async) forEach(iterable, iteratee) → {Promise} +

+ + + + + +
+

Calls a function on each element of iterable.

+

Multiple calls to iteratee will be performed in parallel.

+

If any of the calls to iteratee throws an exception the returned promise will be rejected.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved when all the calls to iteratee have been done. +This promise will be rejected if any call to iteratee throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { forEach, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  await forEach(array, async (v) => {
+    // these calls will be performed in parallel
+    await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+    console.log(v)
+  })
+  // prints 1, 2 and 3 in a random order
+})
+ +
+ + + + + + + +

+ # + (async) forEachLimit(iterable, iteratee, concurrency) → {Promise} +

+ + + + + +
+

Calls a function on each element of iterable.

+

Multiple calls to iteratee will be performed in parallel, up to the concurrency limit.

+

If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining +pending tasks will be cancelled.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
concurrency + + +number + + + +

The number of times iteratee can be called concurrently.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved when all the calls to iteratee have been done. +This promise will be rejected if any call to iteratee throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { forEachLimit, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  await forEachLimit(array, async (v) => {
+    // these calls will be performed in parallel with a maximum of 2
+    // concurrent calls
+    await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+    console.log(v)
+  }, 2)
+  // prints 1, 2 and 3 in a random order (it will always print 1 or 2 before printing 3 due to
+  // the concurrency limit and the internal scheduling order)
+})
+ +
+ + + + + + + +

+ # + (async) forEachSeries(iterable, iteratee) → {Promise} +

+ + + + + +
+

Calls a function on each element of iterable.

+

Multiple calls to iteratee will be performed sequentially.

+

If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining +pending tasks will be cancelled.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved when all the calls to iteratee have been done. +This promise will be rejected if any call to iteratee throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { forEachSeries, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  await forEachSeries(array, async (v) => {
+    // these calls will be performed sequentially
+    await sleep(Math.random() * 10) // waits a random amount of time between 0ms and 10ms
+    console.log(v)
+  })
+  // prints 1, 2 and 3 in that exact order
+})
+ +
+ + + + + + + +

+ # + (async) map(iterable, iteratee) → {Promise} +

+ + + + + +
+

Produces a new collection of values by mapping each value in iterable through the iteratee function.

+

Multiple calls to iteratee will be performed in parallel.

+

If any of the calls to iteratee throws an exception the returned promise will be rejected.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with an array containing all the mapped value, +or will be rejected if any of the calls to iteratee throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { map, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await map(array, async (v) => {
+    // these calls will be performed in parallel
+    await sleep(10) // waits 10ms
+    return v * 2
+  })
+  console.log(result) // prints [2, 4, 6]
+  // total processing time should be ~ 10ms
+})
+ +
+ + + + + + + +

+ # + (async) mapLimit(iterable, iteratee, concurrency) → {Promise} +

+ + + + + +
+

Produces a new collection of values by mapping each value in iterable through the iteratee function.

+

Multiple calls to iteratee will be performed in parallel, up to the concurrency limit.

+

If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining +pending tasks will be cancelled.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
concurrency + + +number + + + +

The number of times iteratee can be called concurrently.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with an array containing all the mapped value, +or will be rejected if any of the calls to iteratee throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { mapLimit, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await mapLimit(array, async (v) => {
+    // these calls will be performed in parallel with a maximum of 2
+    // concurrent calls
+    await sleep(10) // waits 10ms
+    return v * 2
+  }, 2)
+  console.log(result) // prints [2, 4, 6]
+  // total processing time should be ~ 20ms
+})
+ +
+ + + + + + + +

+ # + (async) mapSeries(iterable, iteratee) → {Promise} +

+ + + + + +
+

Produces a new collection of values by mapping each value in iterable through the iteratee function.

+

Multiple calls to iteratee will be performed sequentially.

+

If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining +pending tasks will be cancelled.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with an array containing all the mapped value, +or will be rejected if any of the calls to iteratee throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { mapSeries, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await mapSeries(array, async (v) => {
+    // these calls will be performed sequentially
+    await sleep(10) // waits 10ms
+    return v * 2
+  }, 2)
+  console.log(result) // prints [2, 4, 6]
+  // total processing time should be ~ 30ms
+})
+ +
+ + + + + + + +

+ # + (async) reduce(iterable, reducer, initial) → {Promise} +

+ + + + + +
+

Performs a reduce operation as defined in the Array.reduce() method but using an asynchronous +function as reducer. The reducer will be called sequentially.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

reducer + + +function + + + +

The reducer function. It will be called with four arguments:

+
    +
  • accumulator: The last calculated value (or the first value of the iterable if no initial value is provided)
  • +
  • value: The current value
  • +
  • index: The current index in the iterable. Will start from 0 if no initial value is provided, 1 otherwise.
  • +
  • iterable: The iterable on which the reduce operation is performed.
  • +
initial + + +* + + + +

The initial value that will be used as accumulator in the first call to +reducer. If omitted the first element of iterable will be used as accumulator and reducer +will only be called from from the second element of the list (as defined in the Array.reduce() +function).

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with the result of the reduce operation, +or rejected if any of the calls to reducer throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { reduce, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await reduce(array, async (v, p) => {
+    // these calls will be performed sequentially
+    await sleep(10) // waits 10ms
+    return v + p
+  })
+  console.log(result) // prints 6
+  // total processing time should be ~ 20ms
+})
+ +
+ + + + + + + +

+ # + (async) reduceRight(iterable, reducer, initial) → {Promise} +

+ + + + + +
+

Performs a reduce operation as defined in the Array.reduceRight() method but using an asynchronous +function as reducer. The reducer will be called sequentially.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

reducer + + +function + + + +

The reducer function. It will be called with four arguments:

+
    +
  • accumulator: The last calculated value (or the first value of the iterable if no initial value is provided)
  • +
  • value: The current value
  • +
  • index: The current index in the iterable. Will start from the last index if no initial value is provided, +the last index minus 1 otherwise.
  • +
  • iterable: The iterable on which the reduce operation is performed.
  • +
initial + + +* + + + +

The initial value that will be used as accumulator in the first call to +reducer. If omitted the first element of iterable will be used as accumulator and reducer +will only be called from from the second element of the list (as defined in the Array.reduce() +function).

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved with the result of the reduce operation, +or rejected if any of the calls to reducer throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { reduceRight, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await reduceRight(array, async (v, p) => {
+    // these calls will be performed sequentially
+    await sleep(10) // waits 10ms
+    return v + p
+  })
+  console.log(result) // prints 6
+  // total processing time should be ~ 20ms
+})
+ +
+ + + + + + + +

+ # + (async) sleep(amount) → {Promise} +

+ + + + + +
+

Waits a given amount of time.

+

This function uses setTimeout() internally and has the same behavior, notably that it could resolve +after the asked time (depending on other tasks running in the event loop) or a few milliseconds before.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
amount + + +number + + + +

An amount of time in milliseconds

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved after the given amount of time has passed.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Examples + +
import { sleep, asyncRoot } from 'modern-async'
+
+asyncRoot(async () => {
+  await sleep(100) // will wait 100ms
+})
+ +
// another example that doesn't block on the sleep call
+// it's functionally identical to using setTimout but with a promise syntax
+import { sleep } from 'modern-async'
+
+sleep(10).then(() => {
+  console.log('hello')
+})
+// will print 'hello' after 10ms
+ +
+ + + + + + + +

+ # + sleepCancellable(amount) → {Array} +

+ + + + + +
+

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 uses setTimeout() internally and has the same behavior, notably that it could resolve +after the asked time (depending on other tasks running in the event loop) or a few milliseconds before.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
amount + + +number + + + +

An amount of time in milliseconds

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

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.
  • +
+
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ +
+ + + +
+ Example + +
import { sleepCancellable, asyncRoot } from 'modern-async'
+
+asyncRoot(async () => {
+  const [promise, cancel] = sleepCancellable(100) // schedule to resolve the promise after 100ms
+
+  cancel()
+
+  try {
+    await promise
+  } catch (e) {
+    console.log(e.name) // prints CancelledError
+  }
+})
+ +
+ + + + + + + +

+ # + (async) sleepPrecise(amount) → {Promise} +

+ + + + + +
+

Waits a given amount of time.

+

This function is similar to sleep() 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.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
amount + + +number + + + +

An amount of time in milliseconds

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved after the given amount of time has passed.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { sleepPrecise, asyncRoot } from 'modern-async'
+
+asyncRoot(async () => {
+  await sleepPrecise(100) // will wait 100ms
+})
+ +
+ + + + + + + +

+ # + sleepPreciseCancellable(amount) → {Array} +

+ + + + + +
+

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 sleep() 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.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
amount + + +number + + + +

An amount of time in milliseconds

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

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.
  • +
+
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ +
+ + + +
+ Example + +
import { sleepPreciseCancellable, asyncRoot } from 'modern-async'
+
+asyncRoot(async () => {
+  const [promise, cancel] = sleepPreciseCancellable(100) // schedule to resolve the promise after 100ms
+
+  cancel()
+
+  try {
+    await promise
+  } catch (e) {
+    console.log(e.name) // prints CancelledError
+  }
+})
+ +
+ + + + + + + +

+ # + (async) some(iterable, iteratee) → {Promise} +

+ + + + + +
+

Returns true if at least one element of an iterable pass a truth test and false otherwise.

+

The calls to iteratee will run in parallel. If any truth test returns true the promise is immediately resolved.

+

In case of exception in one of the iteratee calls the promise returned by this function will be rejected +with the exception. In the very specific case where a test returns true and an already started task throws +an exception that exception will be plainly ignored.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved to true if at least one value pass the truth test and false +if none of them do. That promise will be rejected if one of the truth test throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { some, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+
+  const result = await some(array, async (v) => {
+    // these calls will be performed in parallel
+    await sleep(10) // waits 10ms
+    return v % 2 === 0
+  })
+  console.log(result) // prints true
+  // total processing time should be ~ 10ms
+})
+ +
+ + + + + + + +

+ # + (async) someLimit(iterable, iteratee, concurrency) → {Promise} +

+ + + + + +
+

Returns true if at least one element of an iterable pass a truth test and false otherwise.

+

The calls to iteratee will run in parallel, up to a concurrency limit. If any truth test returns true +the promise is immediately resolved.

+

Whenever a test returns true, all the remaining tasks will be cancelled as long +as they didn't started already. In case of exception in one of the iteratee calls the promise +returned by this function will be rejected with the exception and the remaining pending +tasks will also be cancelled. In the very specific case where a test returns true and an +already started task throws an exception that exception will be plainly ignored.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
concurrency + + +number + + + +

The number of times iteratee can be called concurrently.

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved to true if at least one value pass the truth test and false +if none of them do. That promise will be rejected if one of the truth test throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { someLimit, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+
+  const result = await someLimit(array, async (v) => {
+    // these calls will be performed in parallel with a maximum of 2
+    // concurrent calls
+    await sleep(10) // waits 10ms
+    return v % 2 === 0
+  }, 2)
+  console.log(result) // prints true
+  // total processing time should be ~ 10ms
+})
+ +
+ + + + + + + +

+ # + (async) someSeries(iterable, iteratee) → {Promise} +

+ + + + + +
+

Returns true if all elements of an iterable pass a truth test and false otherwise.

+

The calls to iteratee will run sequentially. If any truth test returns true the promise is +immediately resolved.

+

In case of exception in one of the iteratee calls the promise returned by this function will be +rejected with the exception and the remaining pending tasks will be cancelled.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
iterable + + +Iterable + + + +

An iterable object.

iteratee + + +function + + + +

A function that will be called with each member of the iterable. It will receive +three arguments:

+
    +
  • value: The current value to process
  • +
  • index: The index in the iterable. Will start from 0.
  • +
  • iterable: The iterable on which the operation is being performed.
  • +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved to true if at least one value pass the truth test and false +if none of them do. That promise will be rejected if one of the truth test throws an exception.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { someSeries, asyncRoot, sleep } from 'modern-async'
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+
+  const result = await someSeries(array, async (v) => {
+    // these calls will be performed sequentially
+    await sleep(10) // waits 10ms
+    return v % 2 === 0
+  })
+  console.log(result) // prints true
+  // total processing time should be ~ 20ms
+})
+ +
+ + + + + + + +

+ # + (async) timeout(fct, amount) → {Promise} +

+ + + + + +
+

Wraps a call to an asynchronous function to add a timer on it. If the delay is exceeded +the returned promise will be rejected with a TimeoutError.

+

This function uses setTimeout() internally and has the same behavior, notably that it could reject +after the asked time (depending on other tasks running in the event loop) or a few milliseconds before.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fct + + +function + + + +

An asynchronous function that will be called immediately without arguments.

amount + + +number + + + +

An amount of time in milliseconds

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved or rejected according to the result of the call +to fct. If amount milliseconds pass before the call to fct returns or rejects, this promise will +be rejected with a TimeoutError.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { timeout, sleep, asyncRoot } from 'modern-async'
+
+asyncRoot(async () => {
+  // the following statement will perform successfully because
+  // the function will return before the delay
+  await timeout(async () => {
+    await sleep(10)
+  }, 100)
+
+  try {
+    // the following statement will throw after 10ms
+    await timeout(async () => {
+      await sleep(100)
+    }, 10)
+  } catch (e) {
+    console.log(e.name) // prints TimeoutError
+  }
+})
+ +
+ + + + + + + +

+ # + (async) timeoutPrecise(fct, amount) → {Promise} +

+ + + + + +
+

Wraps a call to an asynchronous function to add a timer on it. If the delay is exceeded +the returned promise will be rejected with a TimeoutError.

+

This function is similar to timeout() 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.

+
+ + + + + + + + + +
+ Parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fct + + +function + + + +

An asynchronous function that will be called immediately without arguments.

amount + + +number + + + +

An amount of time in milliseconds

+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Source:
+
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Returns: + + +
+

A promise that will be resolved or rejected according to the result of the call +to fct. If amount milliseconds pass before the call to fct returns or rejects, this promise will +be rejected with a TimeoutError.

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ +
+ + + +
+ Example + +
import { timeoutPrecise, sleep, asyncRoot } from 'modern-async'
+
+asyncRoot(async () => {
+  // the following statement will perform successfully because
+  // the function will return before the delay
+  await timeoutPrecise(async () => {
+    await sleep(10)
+  }, 100)
+
+  try {
+    // the following statement will throw after 10ms
+    await timeoutPrecise(async () => {
+      await sleep(100)
+    }, 10)
+  } catch (e) {
+    console.log(e.name) // prints TimeoutError
+  }
+})
+ +
+ + + + + + + + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/modern-async/1.0.4/index.html b/docs/modern-async/1.0.4/index.html new file mode 100644 index 0000000..2185f8d --- /dev/null +++ b/docs/modern-async/1.0.4/index.html @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Home + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+

modern-async Tweet

+

logo

+

GitHub Repo stars Website +Node.js CI npm Coverage Status

+

A modern JavaScript tooling library for asynchronous operations using async/await and promises.

+

This library is a modernized alternative to a lot of libraries like Async.js that were created using the legacy callback style to handle asynchronous operations. Its goal is to be as complete as any of those libraries while being built from the very beginning with async/await and promises in mind.

+

See the documentation.

+
    +
  • Exclusively uses async/await and promises in its code, tests and documentation.
  • +
  • Has low bundle size.
  • +
  • Has 100% code coverage.
  • +
  • Bundled for ESM modules, CommonJS and UMD.
  • +
  • Works in node >= 8.0 and in the vast majority of browsers (very old browser compatibility can be achieved using Babel and shims).
  • +
+

Stargazers repo roster for @nicolas-van/modern-async

+

This project accepts feature requests !

+

The goal of modern-async is to be as complete as possible. I coded everything I missed in the past while developing, yet it's difficult to know what other people would really need. So if you would like some more feature the issue tracker is available. (Read also the contribution guide).

+

Installation

+
npm install --save modern-async
+
+

Or use jsDelivr to get the UMD version. The content of the library will be available under the modernAsync global variable.

+

Usage

+
import { map, asyncRoot, sleep } from 'modern-async'
+
+// or
+
+const { map, asyncRoot, sleep } = require('modern-async')
+
+asyncRoot(async () => {
+  const array = [1, 2, 3]
+  const result = await map(array, async (v) => {
+    await sleep(10)
+    return v * 2
+  })
+  console.log(result)
+})
+
+

See the documentation for the rest.

+

Changelog

+

The changelog.

+

Contribution Guide

+

The contribution guide

+

License

+

The license.

+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/modern-async/1.0.4/map.mjs.html b/docs/modern-async/1.0.4/map.mjs.html new file mode 100644 index 0000000..bda76f2 --- /dev/null +++ b/docs/modern-async/1.0.4/map.mjs.html @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + map.mjs + + + + + + + + + + + + + + + + + + + +
+ +

map.mjs

+ + + + + + + +
+
+

+import mapLimit from './mapLimit.mjs'
+
+/**
+ * Produces a new collection of values by mapping each value in `iterable` through the `iteratee` function.
+ *
+ * Multiple calls to `iteratee` will be performed in parallel.
+ *
+ * If any of the calls to iteratee throws an exception the returned promise will be rejected.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved with an array containing all the mapped value,
+ * or will be rejected if any of the calls to `iteratee` throws an exception.
+ * @example
+ * import { map, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await map(array, async (v) => {
+ *     // these calls will be performed in parallel
+ *     await sleep(10) // waits 10ms
+ *     return v * 2
+ *   })
+ *   console.log(result) // prints [2, 4, 6]
+ *   // total processing time should be ~ 10ms
+ * })
+ */
+async function map (iterable, iteratee) {
+  return mapLimit(iterable, iteratee, Number.POSITIVE_INFINITY)
+}
+
+export default map
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/mapLimit.mjs.html b/docs/modern-async/1.0.4/mapLimit.mjs.html new file mode 100644 index 0000000..eb838e1 --- /dev/null +++ b/docs/modern-async/1.0.4/mapLimit.mjs.html @@ -0,0 +1,237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mapLimit.mjs + + + + + + + + + + + + + + + + + + + +
+ +

mapLimit.mjs

+ + + + + + + +
+
+

+import Queue from './Queue.mjs'
+import assert from 'nanoassert'
+import CancelledError from './CancelledError.mjs'
+
+/**
+ * Produces a new collection of values by mapping each value in `iterable` through the `iteratee` function.
+ *
+ * Multiple calls to `iteratee` will be performed in parallel, up to the concurrency limit.
+ *
+ * If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining
+ * pending tasks will be cancelled.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @param {number} concurrency The number of times `iteratee` can be called concurrently.
+ * @returns {Promise} A promise that will be resolved with an array containing all the mapped value,
+ * or will be rejected if any of the calls to `iteratee` throws an exception.
+ * @example
+ * import { mapLimit, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await mapLimit(array, async (v) => {
+ *     // these calls will be performed in parallel with a maximum of 2
+ *     // concurrent calls
+ *     await sleep(10) // waits 10ms
+ *     return v * 2
+ *   }, 2)
+ *   console.log(result) // prints [2, 4, 6]
+ *   // total processing time should be ~ 20ms
+ * })
+ */
+async function mapLimit (iterable, iteratee, concurrency) {
+  assert(typeof iteratee === 'function', 'iteratee must be a function')
+  const queue = new Queue(concurrency)
+  queue._cancelledErrorClass = CustomCancelledError
+  const promises = []
+  let current = promises
+  let finalized = false
+  const finalize = () => {
+    if (!finalized) {
+      current.forEach((p) => {
+        p.catch(() => {
+          // ignore the exception
+        })
+      })
+      queue.cancelAllPending()
+    }
+    finalized = true
+  }
+  let i = 0
+  for (const el of iterable) {
+    const index = i
+    promises.push((async () => {
+      try {
+        const gres = await queue.exec(async () => {
+          try {
+            const res = await iteratee(el, index, iterable)
+            return res
+          } catch (e) {
+            finalize()
+            throw e
+          }
+        })
+        return [index, 'resolved', gres]
+      } catch (e) {
+        return [index, 'rejected', e]
+      }
+    })())
+    i += 1
+  }
+
+  const results = []
+
+  try {
+    while (current.length > 0) {
+      const [index, state, result] = await Promise.race(current)
+      if (state === 'resolved') {
+        results[index] = result
+      } else { // error
+        if (!(result instanceof CustomCancelledError)) {
+          throw result
+        }
+      }
+      promises[index] = null
+      current = promises.filter((p) => p !== null)
+    }
+    return results
+  } finally {
+    finalize()
+  }
+}
+
+/**
+ * @ignore
+ */
+class CustomCancelledError extends CancelledError {}
+
+export default mapLimit
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/mapSeries.mjs.html b/docs/modern-async/1.0.4/mapSeries.mjs.html new file mode 100644 index 0000000..df2216f --- /dev/null +++ b/docs/modern-async/1.0.4/mapSeries.mjs.html @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mapSeries.mjs + + + + + + + + + + + + + + + + + + + +
+ +

mapSeries.mjs

+ + + + + + + +
+
+

+import mapLimit from './mapLimit.mjs'
+
+/**
+ * Produces a new collection of values by mapping each value in `iterable` through the `iteratee` function.
+ *
+ * Multiple calls to `iteratee` will be performed sequentially.
+ *
+ * If any of the calls to iteratee throws an exception the returned promise will be rejected and the remaining
+ * pending tasks will be cancelled.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
+ * three arguments:
+ *   * `value`: The current value to process
+ *   * `index`: The index in the iterable. Will start from 0.
+ *   * `iterable`: The iterable on which the operation is being performed.
+ * @returns {Promise} A promise that will be resolved with an array containing all the mapped value,
+ * or will be rejected if any of the calls to `iteratee` throws an exception.
+ * @example
+ * import { mapSeries, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await mapSeries(array, async (v) => {
+ *     // these calls will be performed sequentially
+ *     await sleep(10) // waits 10ms
+ *     return v * 2
+ *   }, 2)
+ *   console.log(result) // prints [2, 4, 6]
+ *   // total processing time should be ~ 30ms
+ * })
+ */
+async function mapSeries (iterable, iteratee) {
+  return mapLimit(iterable, iteratee, 1)
+}
+
+export default mapSeries
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/reduce.mjs.html b/docs/modern-async/1.0.4/reduce.mjs.html new file mode 100644 index 0000000..1cbdb96 --- /dev/null +++ b/docs/modern-async/1.0.4/reduce.mjs.html @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + reduce.mjs + + + + + + + + + + + + + + + + + + + +
+ +

reduce.mjs

+ + + + + + + +
+
+

+import assert from 'nanoassert'
+
+/**
+ * Performs a reduce operation as defined in the `Array.reduce()` method but using an asynchronous
+ * function as reducer. The reducer will be called sequentially.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} reducer The reducer function. It will be called with four arguments:
+ *   * `accumulator`: The last calculated value (or the first value of the iterable if no initial value is provided)
+ *   * `value`: The current value
+ *   * `index`: The current index in the iterable. Will start from 0 if no initial value is provided, 1 otherwise.
+ *   * `iterable`: The iterable on which the reduce operation is performed.
+ * @param {*} initial The initial value that will be used as accumulator in the first call to
+ *   `reducer`. If omitted the first element of `iterable` will be used as accumulator and `reducer`
+ *   will only be called from from the second element of the list (as defined in the `Array.reduce()`
+ *   function).
+ * @returns {Promise} A promise that will be resolved with the result of the reduce operation,
+ *   or rejected if any of the calls to `reducer` throws an exception.
+ * @example
+ * import { reduce, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await reduce(array, async (v, p) => {
+ *     // these calls will be performed sequentially
+ *     await sleep(10) // waits 10ms
+ *     return v + p
+ *   })
+ *   console.log(result) // prints 6
+ *   // total processing time should be ~ 20ms
+ * })
+ */
+async function reduce (iterable, reducer, initial = undefined) {
+  assert(typeof reducer === 'function', 'reducer must be a function')
+  if (initial !== undefined) {
+    let current = initial
+    let i = 0
+    for (const el of iterable) {
+      current = await reducer(current, el, i, iterable)
+      i += 1
+    }
+    return current
+  } else {
+    let i = 0
+    let current
+    for (const el of iterable) {
+      if (i === 0) {
+        current = el
+      } else {
+        current = await reducer(current, el, i, iterable)
+      }
+      i += 1
+    }
+    if (i === 0) {
+      throw new TypeError('Reduce of empty array with no initial value')
+    }
+    return current
+  }
+}
+
+export default reduce
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/reduceRight.mjs.html b/docs/modern-async/1.0.4/reduceRight.mjs.html new file mode 100644 index 0000000..f1a6e8c --- /dev/null +++ b/docs/modern-async/1.0.4/reduceRight.mjs.html @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + reduceRight.mjs + + + + + + + + + + + + + + + + + + + +
+ +

reduceRight.mjs

+ + + + + + + +
+
+

+import reduce from './reduce.mjs'
+
+/**
+ * Performs a reduce operation as defined in the `Array.reduceRight()` method but using an asynchronous
+ * function as reducer. The reducer will be called sequentially.
+ *
+ * @param {Iterable} iterable An iterable object.
+ * @param {Function} reducer The reducer function. It will be called with four arguments:
+ *   * `accumulator`: The last calculated value (or the first value of the iterable if no initial value is provided)
+ *   * `value`: The current value
+ *   * `index`: The current index in the iterable. Will start from the last index if no initial value is provided,
+ *     the last index minus 1 otherwise.
+ *   * `iterable`: The iterable on which the reduce operation is performed.
+ * @param {*} initial The initial value that will be used as accumulator in the first call to
+ *   reducer. If omitted the first element of `iterable` will be used as accumulator and `reducer`
+ *   will only be called from from the second element of the list (as defined in the `Array.reduce()`
+ *   function).
+ * @returns {Promise} A promise that will be resolved with the result of the reduce operation,
+ *   or rejected if any of the calls to `reducer` throws an exception.
+ * @example
+ * import { reduceRight, asyncRoot, sleep } from 'modern-async'
+ *
+ * asyncRoot(async () => {
+ *   const array = [1, 2, 3]
+ *   const result = await reduceRight(array, async (v, p) => {
+ *     // these calls will be performed sequentially
+ *     await sleep(10) // waits 10ms
+ *     return v + p
+ *   })
+ *   console.log(result) // prints 6
+ *   // total processing time should be ~ 20ms
+ * })
+ */
+async function reduceRight (iterable, reducer, initial = undefined) {
+  const arr = Array.from(iterable)
+  arr.reverse()
+  return reduce(arr, (accumulator, value, index, iterable) => {
+    return reducer(accumulator, value, arr.length - 1 - index, iterable)
+  }, initial)
+}
+
+export default reduceRight
+
+
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/scripts/fix-code-block.js b/docs/modern-async/1.0.4/scripts/fix-code-block.js new file mode 100644 index 0000000..23a63e0 --- /dev/null +++ b/docs/modern-async/1.0.4/scripts/fix-code-block.js @@ -0,0 +1,49 @@ +/* global document */ +(function() { + var targets = document.querySelectorAll('pre'); + var main = document.querySelector('#main'); + + var footer = document.querySelector('#footer'); + var pageTitle = document.querySelector('#page-title'); + var pageTitleHeight = 0; + + var footerHeight = footer.getBoundingClientRect().height; + + if (pageTitle) { + pageTitleHeight = pageTitle.getBoundingClientRect().height; + + // Adding margin (Outer height) + pageTitleHeight += 45; + } + + // subtracted 20 for extra padding. + // eslint-disable-next-line no-undef + var divMaxHeight = window.innerHeight - pageTitleHeight - footerHeight - 80; + + setTimeout(function() { + targets.forEach(function(item) { + var innerHTML = item.innerHTML; + var divElement = document.createElement('div'); + + divElement.style.maxHeight = divMaxHeight + 'px'; + divElement.style.marginTop = '2rem'; + divElement.innerHTML = innerHTML; + // item.removeChild(); + item.innerHTML = ''; + item.appendChild(divElement); + }); + + // eslint-disable-next-line no-undef + main.style.minHeight = window.innerHeight - footerHeight - 15 + 'px'; + + // See if we have to move something into view + // eslint-disable-next-line no-undef + var location = window.location.href.split('#')[1]; + + if (location && location.length > 0) { + var element = document.querySelector('#'.concat(location)); + + element.scrollIntoView(); + } + }, 300); +})(); diff --git a/docs/modern-async/1.0.4/scripts/linenumber.js b/docs/modern-async/1.0.4/scripts/linenumber.js new file mode 100644 index 0000000..4656ba1 --- /dev/null +++ b/docs/modern-async/1.0.4/scripts/linenumber.js @@ -0,0 +1,25 @@ +/* global document */ +(function() { + var source = document.getElementsByClassName('prettyprint source linenums'); + var i = 0; + var lineNumber = 0; + var lineId; + var lines; + var totalLines; + var anchorHash; + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; + + for (; i < totalLines; i++) { + lineNumber++; + lineId = 'line' + lineNumber; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } + } +})(); diff --git a/docs/modern-async/1.0.4/scripts/misc.js b/docs/modern-async/1.0.4/scripts/misc.js new file mode 100644 index 0000000..39c11b4 --- /dev/null +++ b/docs/modern-async/1.0.4/scripts/misc.js @@ -0,0 +1,72 @@ +/* global document */ +function copy(value) { + const el = document.createElement('textarea'); + + el.value = value; + document.body.appendChild(el); + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); +} + +function showTooltip(id) { + var tooltip = document.getElementById(id); + + tooltip.classList.add('show-tooltip'); + setTimeout(function() { + tooltip.classList.remove('show-tooltip'); + }, 3000); +} + +/* eslint-disable-next-line */ +function copyFunction(id) { + // selecting the pre element + var code = document.getElementById(id); + + // selecting the ol.linenums + var element = code.querySelector('.linenums'); + + if (!element) { + // selecting the code block + element = code.querySelector('code'); + } + + // copy + copy(element.innerText); + + // show tooltip + showTooltip('tooltip-' + id); +} + +(function() { + // capturing all pre element on the page + var allPre = document.getElementsByTagName('pre'); + + + var i, classList; + + for ( i = 0; i < allPre.length; i++) { + // get the list of class in current pre element + classList = allPre[i].classList; + var id = 'pre-id-' + i; + + // tooltip + var tooltip = '
Copied!
'; + + // template of copy to clipboard icon container + var copyToClipboard = '
' + tooltip + '
'; + + // extract the code language + var langName = classList[classList.length - 1].split('-')[1]; + + if ( langName === undefined ) { langName = 'JavaScript'; } + + // if(langName != undefined) + var langNameDiv = '
' + langName.toLocaleUpperCase() + '
'; + // else langNameDiv = ''; + + // appending everything to the current pre element + allPre[i].innerHTML += '
' + langNameDiv + copyToClipboard + '
'; + allPre[i].setAttribute('id', id); + } +})(); diff --git a/docs/modern-async/1.0.4/scripts/search.js b/docs/modern-async/1.0.4/scripts/search.js new file mode 100644 index 0000000..04c0b10 --- /dev/null +++ b/docs/modern-async/1.0.4/scripts/search.js @@ -0,0 +1,72 @@ +/* global document */ +function hideSearchList() { + document.getElementById('search-item-ul').style.display = 'none'; +} + +function showSearchList() { + document.getElementById('search-item-ul').style.display = 'block'; +} + +function checkClick(e) { + if ( e.target.id !== 'search-box') { + setTimeout(function() { + hideSearchList(); + }, 60); + + /* eslint-disable-next-line */ + window.removeEventListener('click', checkClick); + } +} + +function search(list, keys, searchKey) { + var options = { + shouldSort: true, + threshold: 0.4, + location: 0, + distance: 100, + maxPatternLength: 32, + minMatchCharLength: 1, + keys: keys + }; + + /* eslint-disable-next-line */ + var fuse = new Fuse(list, options); + var result = fuse.search(searchKey); + var searchUL = document.getElementById('search-item-ul'); + + searchUL.innerHTML = ''; + + if (result.length === 0) { + searchUL.innerHTML += '
  • No Result Found
  • '; + } else { + result.forEach(function(item) { + searchUL.innerHTML += '
  • ' + item.link + '
  • '; + }); + } +} + +/* eslint-disable-next-line */ +function setupSearch(list) { + var inputBox = document.getElementById('search-box'); + var keys = ['title']; + + inputBox.addEventListener('keyup', function() { + if (inputBox.value !== '') { + showSearchList(); + search(list, keys, inputBox.value); + } + else { hideSearchList(); } + }); + + inputBox.addEventListener('focus', function() { + showSearchList(); + if (inputBox.value !== '') { + search(list, keys, inputBox.value); + } + + /* eslint-disable-next-line */ + window.addEventListener('click', checkClick); + }); +} + + diff --git a/docs/modern-async/1.0.4/scripts/third-party/Apache-License-2.0.txt b/docs/modern-async/1.0.4/scripts/third-party/Apache-License-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/docs/modern-async/1.0.4/scripts/third-party/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/docs/modern-async/1.0.4/scripts/third-party/fuse.js b/docs/modern-async/1.0.4/scripts/third-party/fuse.js new file mode 100644 index 0000000..71fa56a --- /dev/null +++ b/docs/modern-async/1.0.4/scripts/third-party/fuse.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("Fuse",[],t):"object"==typeof exports?exports.Fuse=t():e.Fuse=t()}(this,function(){return n={},o.m=r=[function(e,t){e.exports=function(e){return Array.isArray?Array.isArray(e):"[object Array]"===Object.prototype.toString.call(e)}},function(e,t,r){function l(e){return(l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function n(e,t){for(var r=0;r 0 and <= 1");d=d.name}else s[d]={weight:1};this._analyze({key:d,value:this.options.getFn(l,d),record:l,index:c},{resultMap:n,results:o,tokenSearchers:e,fullSearcher:t})}return{weights:s,results:o}}},{key:"_analyze",value:function(e,t){var r=e.key,n=e.arrayIndex,o=void 0===n?-1:n,i=e.value,a=e.record,s=e.index,c=t.tokenSearchers,h=void 0===c?[]:c,l=t.fullSearcher,u=void 0===l?[]:l,f=t.resultMap,d=void 0===f?{}:f,v=t.results,p=void 0===v?[]:v;if(null!=i){var g=!1,y=-1,m=0;if("string"==typeof i){this._log("\nKey: ".concat(""===r?"-":r));var k=u.search(i);if(this._log('Full text: "'.concat(i,'", score: ').concat(k.score)),this.options.tokenize){for(var S=i.split(this.options.tokenSeparator),x=[],b=0;b=h.length;if(this._log("\nCheck Matches: ".concat(P)),(g||k.isMatch)&&P){var F=d[s];F?F.output.push({key:r,arrayIndex:o,value:i,score:j,matchedIndices:k.matchedIndices}):(d[s]={item:a,output:[{key:r,arrayIndex:o,value:i,score:j,matchedIndices:k.matchedIndices}]},p.push(d[s]))}}else if(E(i))for(var T=0,z=i.length;Tr)return l(e,this.pattern,n);var o=this.options,i=o.location,a=o.distance,s=o.threshold,c=o.findAllMatches,h=o.minMatchCharLength;return u(e,this.pattern,this.patternAlphabet,{location:i,distance:a,threshold:s,findAllMatches:c,minMatchCharLength:h})}}]),k);function k(e,t){var r=t.location,n=void 0===r?0:r,o=t.distance,i=void 0===o?100:o,a=t.threshold,s=void 0===a?.6:a,c=t.maxPatternLength,h=void 0===c?32:c,l=t.isCaseSensitive,u=void 0!==l&&l,f=t.tokenSeparator,d=void 0===f?/ +/g:f,v=t.findAllMatches,p=void 0!==v&&v,g=t.minMatchCharLength,y=void 0===g?1:g;!function(e){if(!(e instanceof k))throw new TypeError("Cannot call a class as a function")}(this),this.options={location:n,distance:i,threshold:s,maxPatternLength:h,isCaseSensitive:u,tokenSeparator:d,findAllMatches:p,minMatchCharLength:y},this.pattern=this.options.isCaseSensitive?e:e.toLowerCase(),this.pattern.length<=h&&(this.patternAlphabet=m(this.pattern))}e.exports=o},function(e,t){var l=/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;e.exports=function(e,t){var r=2g)break;M=P}return{isMatch:0<=y,score:0===_?.001:_,matchedIndices:K(k,d)}}},function(e,t){e.exports=function(e,t){var r=t.errors,n=void 0===r?0:r,o=t.currentLocation,i=void 0===o?0:o,a=t.expectedLocation,s=void 0===a?0:a,c=t.distance,h=void 0===c?100:c,l=n/e.length,u=Math.abs(s-i);return h?l+u/h:u?1:l}},function(e,t){e.exports=function(){for(var e=0=t&&r.push([n,o]),n=-1)}return e[i-1]&&t<=i-n&&r.push([n,i-1]),r}},function(e,t){e.exports=function(e){for(var t={},r=e.length,n=0;n)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/docs/modern-async/1.0.4/scripts/third-party/prettify.js b/docs/modern-async/1.0.4/scripts/third-party/prettify.js new file mode 100644 index 0000000..eef5ad7 --- /dev/null +++ b/docs/modern-async/1.0.4/scripts/third-party/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sleep.mjs + + + + + + + + + + + + + + + + + + + +
    + +

    sleep.mjs

    + + + + + + + +
    +
    +
    
    +import sleepCancellable from './sleepCancellable.mjs'
    +
    +/**
    + * Waits a given amount of time.
    + *
    + * This function uses `setTimeout()` internally and has the same behavior, notably that it could resolve
    + * after the asked time (depending on other tasks running in the event loop) or a few milliseconds before.
    + *
    + * @param {number} amount An amount of time in milliseconds
    + * @returns {Promise} A promise that will be resolved after the given amount of time has passed.
    + * @example
    + * import { sleep, asyncRoot } from 'modern-async'
    + *
    + * asyncRoot(async () => {
    + *   await sleep(100) // will wait 100ms
    + * })
    + * @example
    + * // another example that doesn't block on the sleep call
    + * // it's functionally identical to using setTimout but with a promise syntax
    + * import { sleep } from 'modern-async'
    + *
    + * sleep(10).then(() => {
    + *   console.log('hello')
    + * })
    + * // will print 'hello' after 10ms
    + */
    +async function sleep (amount) {
    +  return sleepCancellable(amount)[0]
    +}
    +
    +export default sleep
    +
    +
    +
    + + + + +
    + +
    + modern-async is licensed under the terms of the MIT license +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/sleepCancellable.mjs.html b/docs/modern-async/1.0.4/sleepCancellable.mjs.html new file mode 100644 index 0000000..448dbc6 --- /dev/null +++ b/docs/modern-async/1.0.4/sleepCancellable.mjs.html @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sleepCancellable.mjs + + + + + + + + + + + + + + + + + + + +
    + +

    sleepCancellable.mjs

    + + + + + + + +
    +
    +
    
    +import assert from 'nanoassert'
    +import Deferred from './Deferred.mjs'
    +import CancelledError from './CancelledError.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 uses `setTimeout()` internally and has the same behavior, notably that it could resolve
    + * after the asked time (depending on other tasks running in the event loop) or a few milliseconds before.
    + *
    + * @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 { sleepCancellable, asyncRoot } from 'modern-async'
    + *
    + * asyncRoot(async () => {
    + *   const [promise, cancel] = sleepCancellable(100) // schedule to resolve the promise after 100ms
    + *
    + *   cancel()
    + *
    + *   try {
    + *     await promise
    + *   } catch (e) {
    + *     console.log(e.name) // prints CancelledError
    + *   }
    + * })
    + */
    +function sleepCancellable (amount) {
    +  assert(typeof amount === 'number', 'amount must be a number')
    +  let id
    +  const deferred = new Deferred()
    +  setTimeout(deferred.resolve, amount)
    +  let terminated = false
    +  return [deferred.promise.finally(() => {
    +    terminated = true
    +  }), () => {
    +    if (terminated) {
    +      return false
    +    } else {
    +      terminated = true
    +      deferred.reject(new CancelledError())
    +      clearTimeout(id)
    +      return true
    +    }
    +  }]
    +}
    +
    +export default sleepCancellable
    +
    +
    +
    + + + + +
    + +
    + modern-async is licensed under the terms of the MIT license +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/sleepPrecise.mjs.html b/docs/modern-async/1.0.4/sleepPrecise.mjs.html new file mode 100644 index 0000000..5848101 --- /dev/null +++ b/docs/modern-async/1.0.4/sleepPrecise.mjs.html @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sleepPrecise.mjs + + + + + + + + + + + + + + + + + + + +
    + +

    sleepPrecise.mjs

    + + + + + + + +
    +
    +
    
    +import sleepPreciseCancellable from './sleepPreciseCancellable.mjs'
    +
    +/**
    + * Waits a given amount of time.
    + *
    + * This function is similar to `sleep()` 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 {Promise} A promise that will be resolved after the given amount of time has passed.
    + * @example
    + * import { sleepPrecise, asyncRoot } from 'modern-async'
    + *
    + * asyncRoot(async () => {
    + *   await sleepPrecise(100) // will wait 100ms
    + * })
    + */
    +async function sleepPrecise (amount) {
    +  return sleepPreciseCancellable(amount)[0]
    +}
    +
    +export default sleepPrecise
    +
    +
    +
    + + + + +
    + +
    + modern-async is licensed under the terms of the MIT license +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/sleepPreciseCancellable.mjs.html b/docs/modern-async/1.0.4/sleepPreciseCancellable.mjs.html new file mode 100644 index 0000000..57405fe --- /dev/null +++ b/docs/modern-async/1.0.4/sleepPreciseCancellable.mjs.html @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sleepPreciseCancellable.mjs + + + + + + + + + + + + + + + + + + + +
    + +

    sleepPreciseCancellable.mjs

    + + + + + + + +
    +
    +
    
    +import assert from 'nanoassert'
    +import sleepCancellable from './sleepCancellable.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 `sleep()` 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 { sleepPreciseCancellable, asyncRoot } from 'modern-async'
    + *
    + * asyncRoot(async () => {
    + *   const [promise, cancel] = sleepPreciseCancellable(100) // schedule to resolve the promise after 100ms
    + *
    + *   cancel()
    + *
    + *   try {
    + *     await promise
    + *   } catch (e) {
    + *     console.log(e.name) // prints CancelledError
    + *   }
    + * })
    + */
    +function sleepPreciseCancellable (amount) {
    +  return _innerWaitPreciseCancellable(amount, (ellasped, amount) => {
    +    return ellasped >= amount
    +  })
    +}
    +
    +export default sleepPreciseCancellable
    +
    +/**
    + * @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] = sleepCancellable(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] = sleepCancellable(amount - ellasped)
    +      lastCancel = ncancel
    +      np.then(resolve, reject)
    +    }
    +  }
    +  p.then(resolve, reject)
    +  return [deferred.promise, () => {
    +    return lastCancel()
    +  }]
    +}
    +
    +export { _innerWaitPreciseCancellable }
    +
    +
    +
    + + + + +
    + +
    + modern-async is licensed under the terms of the MIT license +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/some.mjs.html b/docs/modern-async/1.0.4/some.mjs.html new file mode 100644 index 0000000..cf003cd --- /dev/null +++ b/docs/modern-async/1.0.4/some.mjs.html @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + some.mjs + + + + + + + + + + + + + + + + + + + +
    + +

    some.mjs

    + + + + + + + +
    +
    +
    
    +import someLimit from './someLimit.mjs'
    +
    +/**
    + * Returns `true` if at least one element of an iterable pass a truth test and `false` otherwise.
    + *
    + * The calls to `iteratee` will run in parallel. If any truth test returns `true` the promise is immediately resolved.
    + *
    + * In case of exception in one of the `iteratee` calls the promise returned by this function will be rejected
    + * with the exception. In the very specific case where a test returns `true` and an already started task throws
    + * an exception that exception will be plainly ignored.
    + *
    + * @param {Iterable} iterable An iterable object.
    + * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
    + * three arguments:
    + *   * `value`: The current value to process
    + *   * `index`: The index in the iterable. Will start from 0.
    + *   * `iterable`: The iterable on which the operation is being performed.
    + * @returns {Promise} A promise that will be resolved to `true` if at least one value pass the truth test and `false`
    + * if none of them do. That promise will be rejected if one of the truth test throws an exception.
    + * @example
    + * import { some, asyncRoot, sleep } from 'modern-async'
    + *
    + * asyncRoot(async () => {
    + *   const array = [1, 2, 3]
    + *
    + *   const result = await some(array, async (v) => {
    + *     // these calls will be performed in parallel
    + *     await sleep(10) // waits 10ms
    + *     return v % 2 === 0
    + *   })
    + *   console.log(result) // prints true
    + *   // total processing time should be ~ 10ms
    + * })
    + */
    +async function some (iterable, iteratee) {
    +  return someLimit(iterable, iteratee, Number.POSITIVE_INFINITY)
    +}
    +
    +export default some
    +
    +
    +
    + + + + +
    + +
    + modern-async is licensed under the terms of the MIT license +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/someLimit.mjs.html b/docs/modern-async/1.0.4/someLimit.mjs.html new file mode 100644 index 0000000..1125c91 --- /dev/null +++ b/docs/modern-async/1.0.4/someLimit.mjs.html @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + someLimit.mjs + + + + + + + + + + + + + + + + + + + +
    + +

    someLimit.mjs

    + + + + + + + +
    +
    +
    
    +import findIndexLimit from './findIndexLimit.mjs'
    +
    +/**
    + * Returns `true` if at least one element of an iterable pass a truth test and `false` otherwise.
    + *
    + * The calls to `iteratee` will run in parallel, up to a concurrency limit. If any truth test returns `true`
    + * the promise is immediately resolved.
    + *
    + * Whenever a test returns `true`, all the remaining tasks will be cancelled as long
    + * as they didn't started already. In case of exception in one of the `iteratee` calls the promise
    + * returned by this function will be rejected with the exception and the remaining pending
    + * tasks will also be cancelled. In the very specific case where a test returns `true` and an
    + * already started task throws an exception that exception will be plainly ignored.
    + *
    + * @param {Iterable} iterable An iterable object.
    + * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
    + * three arguments:
    + *   * `value`: The current value to process
    + *   * `index`: The index in the iterable. Will start from 0.
    + *   * `iterable`: The iterable on which the operation is being performed.
    + * @param {number} concurrency The number of times `iteratee` can be called concurrently.
    + * @returns {Promise} A promise that will be resolved to `true` if at least one value pass the truth test and `false`
    + * if none of them do. That promise will be rejected if one of the truth test throws an exception.
    + * @example
    + * import { someLimit, asyncRoot, sleep } from 'modern-async'
    + *
    + * asyncRoot(async () => {
    + *   const array = [1, 2, 3]
    + *
    + *   const result = await someLimit(array, async (v) => {
    + *     // these calls will be performed in parallel with a maximum of 2
    + *     // concurrent calls
    + *     await sleep(10) // waits 10ms
    + *     return v % 2 === 0
    + *   }, 2)
    + *   console.log(result) // prints true
    + *   // total processing time should be ~ 10ms
    + * })
    + */
    +async function someLimit (iterable, iteratee, concurrency) {
    +  const index = await findIndexLimit(iterable, iteratee, concurrency)
    +  const result = index !== -1
    +  return result
    +}
    +
    +export default someLimit
    +
    +
    +
    + + + + +
    + +
    + modern-async is licensed under the terms of the MIT license +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/someSeries.mjs.html b/docs/modern-async/1.0.4/someSeries.mjs.html new file mode 100644 index 0000000..9c477be --- /dev/null +++ b/docs/modern-async/1.0.4/someSeries.mjs.html @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + someSeries.mjs + + + + + + + + + + + + + + + + + + + +
    + +

    someSeries.mjs

    + + + + + + + +
    +
    +
    
    +import someLimit from './someLimit.mjs'
    +
    +/**
    + * Returns `true` if all elements of an iterable pass a truth test and `false` otherwise.
    + *
    + * The calls to `iteratee` will run sequentially. If any truth test returns `true` the promise is
    + * immediately resolved.
    + *
    + * In case of exception in one of the iteratee calls the promise returned by this function will be
    + * rejected with the exception and the remaining pending tasks will be cancelled.
    + *
    + * @param {Iterable} iterable An iterable object.
    + * @param {Function} iteratee A function that will be called with each member of the iterable. It will receive
    + * three arguments:
    + *   * `value`: The current value to process
    + *   * `index`: The index in the iterable. Will start from 0.
    + *   * `iterable`: The iterable on which the operation is being performed.
    + * @returns {Promise} A promise that will be resolved to `true` if at least one value pass the truth test and `false`
    + * if none of them do. That promise will be rejected if one of the truth test throws an exception.
    + * @example
    + * import { someSeries, asyncRoot, sleep } from 'modern-async'
    + *
    + * asyncRoot(async () => {
    + *   const array = [1, 2, 3]
    + *
    + *   const result = await someSeries(array, async (v) => {
    + *     // these calls will be performed sequentially
    + *     await sleep(10) // waits 10ms
    + *     return v % 2 === 0
    + *   })
    + *   console.log(result) // prints true
    + *   // total processing time should be ~ 20ms
    + * })
    + */
    +async function someSeries (iterable, iteratee) {
    +  return someLimit(iterable, iteratee, 1)
    +}
    +
    +export default someSeries
    +
    +
    +
    + + + + +
    + +
    + modern-async is licensed under the terms of the MIT license +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/styles/clean-jsdoc-theme-base.css b/docs/modern-async/1.0.4/styles/clean-jsdoc-theme-base.css new file mode 100644 index 0000000..07019f6 --- /dev/null +++ b/docs/modern-async/1.0.4/styles/clean-jsdoc-theme-base.css @@ -0,0 +1,71 @@ +@font-face { + font-family: 'heading'; + src: url('../fonts/Muli-Black.ttf') format('truetype'); +} + +@font-face { + font-family: 'body'; + src: url('../fonts/Montserrat-Regular.ttf') format('truetype'); +} + +@font-face { + font-family: 'code'; + src: url('../fonts/MavenPro-Regular.ttf') format('truetype'); +} + +pre { + position: relative; +} + +.pre-top-bar-container { + align-items: center; + display: flex; + justify-content: space-between; + left: 0; + padding: 0.3125rem 1.5rem; + position: absolute; + right: 0; + top: 0; +} + +.code-copy-icon-container { + align-items: center; + border-radius: 50%; + cursor: pointer; + display: flex; + height: 1.875rem; + justify-content: center; + transition: 0.3s; + width: 1.875rem; +} + +.code-copy-icon-container > div { + margin-top: 0.25rem; + position: relative; +} + +.sm-icon { + height: 1rem; + width: 1rem; +} + +.code-lang-name { + font-family: 'code'; + font-size: 12px; +} + +.tooltip { + border-radius: 5px; + opacity: 0; + padding: 3px 8px; + position: absolute; + right: 30px; + top: -2px; + transform: scale(0); + transition: 0.3s; +} + +.show-tooltip { + opacity: 1; + transform: scale(1); +} diff --git a/docs/modern-async/1.0.4/styles/clean-jsdoc-theme-dark.css b/docs/modern-async/1.0.4/styles/clean-jsdoc-theme-dark.css new file mode 100644 index 0000000..409fe8b --- /dev/null +++ b/docs/modern-async/1.0.4/styles/clean-jsdoc-theme-dark.css @@ -0,0 +1,324 @@ +body { + background-color: #000; + color: #fff; +} + +a, +a:active { + color: #009bff; +} + +hr { + border: 1px solid #333; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #f7f7f7; +} + +/* stylelint-disable */ + +h1.page-title::after, +article h1::after { + background: #333; +} + +/* stylelint-enable */ + +h4 { + color: #4d4e53; +} + +.subsection-title { + border-bottom: 1px solid #333; +} + +tt, +code, +kbd, +samp { + background: #333; +} + +section { + background-color: #000; +} + +section h2::after { + background: #333; +} + +::selection { + background: #ffce76; + color: #000; +} + +.signature-attributes { + color: #aaa; +} + +nav { + background: #101010; +} + +nav > h2 > a { + color: #fff !important; +} + +/* stylelint-disable */ +nav > h2 > a.filter img { + filter: grayscale(100%) brightness(10); + filter: grayscale(100%) brightness(10); +} + +/* stylelint-enable */ + +.search-box .search-item-container { + background: #222; +} + +.search-item-ul li:hover { + background: #333; +} + +.search-item-ul a, +.search-item-ul a:hover { + color: #fff; +} + +nav h2, +nav h3, +nav h3 a { + color: #fff !important; +} + +/* stylelint-disable */ +.sidebar-list-div > ul > li > a { + color: #c9d1d3; +} + +.sidebar-list-div ul ul a { + color: #c9d1d3; +} +/* stylelint-enable */ + +footer { + background: #101010; + color: #f7f7f7; +} + +.ancestors { + color: #999; +} + +.ancestors a { + color: #999 !important; +} + +.important { + color: #950b02; +} + +.type-signature { + color: #00918e; +} + +.name, +.name a { + color: #f7f7f7; +} + +.details { + background: #222; + border-left: 5px solid #555; + color: #fff; +} + +.member-item-container strong, +.method-member-container strong { + color: #fff; +} + +.prettyprint, +.pre-top-bar-container { + background: #101010; +} + +.prettyprint code { + background-color: #101010; +} + +.prettyprint.linenums li { + border-left: 3px #222831 solid; +} + +/* stylelint-disable */ +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * { + background-color: #404040; +} +/* stylelint-enable */ + +table .name, +.params .name, +.props .name, +.name code { + color: #fff; +} + +table td, +.params td { + background: #1b1b1b; +} + +table thead tr, +.params thead tr, +.props thead tr { + background-color: #101010; + color: #fff; +} + +/* stylelint-disable */ +table .params thead tr, +.params .params thead tr, +.props .props thead tr { + background-color: #001628; + color: #fff; +} + +/* dl.param-type { + border-bottom: 1px solid #555; +} */ + +.disabled { + color: #aaaaaa; +} + +/* navicon */ + +.navicon { + background: #fff; +} + +.navicon::before, +.navicon::after { + background: #fff; +} + +.nav-trigger:checked + label.plus .navicon::before, +.nav-trigger:checked + label.x .navicon::before { + background: #fff; +} + +.nav-trigger:checked + label.plus .navicon::after, +.nav-trigger:checked + label.x .navicon::after { + background: #fff; +} + +.overlay { + background: hsla(0, 0%, 0%, 0.5); +} + +@media only screen and (max-width: 42rem) { + /* Navbar icon button color*/ + + .navicon-button { + background: #222; + } +} + +.code-copy-icon-container { + fill: #fff; +} + +.code-copy-icon-container:hover { + background-color: #333; +} + +.code-lang-name { + color: #ff8a00; +} + +.tooltip { + background: #ffce76; + color: #000; +} + +/* code */ +.pln { + color: #ffdd4a; +} + +.str { + color: #56e39f; +} + +/* a keyword */ +.kwd { + color: #08b2e3; +} + +/* a comment */ +.com { + color: #999; +} + +/* a type name */ +.typ { + color: #ef6f6c; +} + +/* a literal value */ +.lit { + color: #f5d67b; +} + +/* punctuation */ +.pun { + color: #5adbff; +} + +/* lisp open bracket */ +.opn { + color: #72e0d1; +} + +/* lisp close bracket */ +.clo { + color: #72e0d1; +} + +/* a markup tag name */ +.tag { + color: #007bff; +} + +/* a markup attribute name */ +.atn { + color: #f5d67b; +} + +/* a markup attribute value */ +.atv { + color: #3e999f; +} + +/* a declaration */ +.dec { + color: #f5871f; +} + +/* a variable name */ +.var { + color: #f5d67b; +} + +/* a function name */ +.fun { + color: #4271ae; +} diff --git a/docs/modern-async/1.0.4/styles/clean-jsdoc-theme-light.css b/docs/modern-async/1.0.4/styles/clean-jsdoc-theme-light.css new file mode 100644 index 0000000..0c59c61 --- /dev/null +++ b/docs/modern-async/1.0.4/styles/clean-jsdoc-theme-light.css @@ -0,0 +1,343 @@ +body { + background-color: #fff; + color: #4d4e53; +} + +a, +a:active { + color: #530fff; +} + +hr { + border: 1px solid #eee; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #000; +} + +/* stylelint-disable */ + +h1.page-title::after, +article h1::after { + background: #fbe555; +} + +/* stylelint-enable */ + +h4 { + color: #4d4e53; +} + +.subsection-title { + border-bottom: 1px solid #eee; +} + +tt, +code, +kbd, +samp { + background: #f4f4f4; +} + +section { + background-color: #fff; +} + +section h2::after { + background: #eee; +} + +::selection { + background: #ffce76; + color: #1d1919; +} + +::selection { + background: #ffce76; + color: #1d1919; +} + +.signature-attributes { + color: #aaa; +} + +nav { + background: #001628; +} + +nav > h2 > a { + color: #fff !important; +} + +/* stylelint-disable */ +nav > h2 > a.filter img { + filter: grayscale(100%) brightness(10); + filter: grayscale(100%) brightness(10); +} + +/* stylelint-enable */ + +.search-box .search-item-container { + background: #fff; +} + +.search-item-ul li { + color: #999; +} + +.search-item-ul li:hover { + background: #f7f7f7; +} + +.search-item-ul a:hover { + color: #530fff; +} + +nav h2, +nav h3, +nav h3 a { + color: #fff !important; +} + +nav a:hover { + color: #1089ff; +} + +/* stylelint-disable */ +.sidebar-list-div > ul > li > a { + color: #c9d1d3; +} + +.sidebar-list-div ul ul a { + color: #c9d1d3; +} +/* stylelint-enable */ + +footer { + color: #222; + color: #555; +} + +.ancestors { + color: #999; +} + +.ancestors a { + color: #999 !important; +} + +.important { + color: #950b02; +} + +.type-signature { + color: #00918e; +} + +.name, +.name a { + color: #293a80; +} + +.details { + background: #f7f7f7; + border-left: 5px solid #001628; + color: #001628; +} + +.member-item-container strong, +.method-member-container strong { + color: #001628; +} + +.prettyprint, +.pre-top-bar-container { + background: #001628; +} + +.prettyprint code { + background-color: #001628; +} + +.prettyprint.linenums li { + border-left: 3px #222831 solid; +} + +/* stylelint-disable */ +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * { + background-color: #404040; +} +/* stylelint-enable */ + +table, +.params, +.props { + box-shadow: 0 0 15px rgba(0, 0, 0, 0.1); +} + +table .name, +.params .name, +.props .name, +.name code { + color: #4d4e53; +} + +table td, +.params td { + border-top: 1px solid #eee; +} + +table thead tr, +.params thead tr, +.props thead tr { + background-color: #001628; + color: #fff; +} + +/* stylelint-disable */ +table .params thead tr, +.params .params thead tr, +.props .props thead tr { + background-color: #001628; + color: #fff; +} + +/* dl.param-type { + border-bottom: 1px solid hsl(0, 0%, 87%); +} */ + +.disabled { + color: #454545; +} + +/* navicon */ + +.navicon { + background: #000; +} + +.navicon::before, +.navicon::after { + background: #000; +} + +.nav-trigger:checked + label.plus .navicon::before, +.nav-trigger:checked + label.x .navicon::before { + background: #000; +} + +.nav-trigger:checked + label.plus .navicon::after, +.nav-trigger:checked + label.x .navicon::after { + background: #000; +} + +.overlay { + background: hsla(0, 0%, 0%, 0.5); +} + +@media only screen and (max-width: 42rem) { + /* Navbar icon button color*/ + + .navicon-button { + background: #f1f1f1; + } +} + +.code-copy-icon-container { + fill: #fff; +} + +.code-copy-icon-container:hover { + background-color: #fff; + fill: #000; +} + +.code-lang-name { + color: #ff8a00; +} + +.tooltip { + background: #ffce76; + color: #000; +} + +.pln { + color: #f5d67b; +} + +/* string content */ +.str { + color: #55ae95; +} + +/* a keyword */ +.kwd { + color: #5edfff; +} + +/* a comment */ +.com { + color: #a0a0a0; +} + +/* a type name */ +.typ { + color: #f5d67b; +} + +/* a literal value */ +.lit { + color: #f5d67b; +} + +/* punctuation */ +.pun { + color: #72e0d1; +} + +/* lisp open bracket */ +.opn { + color: #72e0d1; +} + +/* lisp close bracket */ +.clo { + color: #72e0d1; +} + +/* a markup tag name */ +.tag { + color: #007bff; +} + +/* a markup attribute name */ +.atn { + color: #f5d67b; +} + +/* a markup attribute value */ +.atv { + color: #3e999f; +} + +/* a declaration */ +.dec { + color: #f5871f; +} + +/* a variable name */ +.var { + color: #f5d67b; +} + +/* a function name */ +.fun { + color: #4271ae; +} diff --git a/docs/modern-async/1.0.4/styles/jsdoc-default.css b/docs/modern-async/1.0.4/styles/jsdoc-default.css new file mode 100644 index 0000000..5cb9c65 --- /dev/null +++ b/docs/modern-async/1.0.4/styles/jsdoc-default.css @@ -0,0 +1,790 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html, +body { + height: 100%; + width: 100%; +} + +html { + display: flex; +} + +body { + font-family: 'body'; + font-size: 16px; + margin: 0 auto; + padding: 0; +} + +a, +a:active { + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +p, +ul, +ol, +blockquote { + margin-bottom: 1em; +} + +ol { + list-style-position: inside; +} + +p { + overflow-x: auto; + width: 100%; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: 'heading'; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: 400; + margin: 0; +} + +h1 { + font-size: 48px; + font-weight: 300; + margin: 1em 0 0.5em; + position: relative; + z-index: 1; +} + +/* stylelint-disable */ +h1.page-title { + font-size: 48px; + margin: 10px 30px 20px; + position: relative; + z-index: 10; +} + +h1.page-title::after, +article h1::after { + bottom: 5px; + content: ''; + display: block; + height: 15px; + position: absolute; + width: 100%; + z-index: -1; +} + +/* stylelint-enable */ + +h2 { + font-size: 24px; + margin: 10px 0; +} + +h3 { + font-size: 20px; + margin: 1.2em 0 0.3em; +} + +h4 { + font-size: 18px; + margin: 1em 0 0.2em; +} + +h5, +.container-overview .subsection-title { + font-size: 120%; + letter-spacing: -0.01em; + margin: 8px 0 3px; +} + +.subsection-title { + text-transform: uppercase; +} + +h6 { + font-size: 100%; + font-style: italic; + letter-spacing: -0.01em; + margin: 6px 0 3px; +} + +tt, +code, +kbd, +samp { + border-radius: 5px; + font-family: 'code'; + font-size: 80%; + padding: 1px 5px; +} + +.class-description { + font-size: 18px; + margin-bottom: 16px; +} + +.class-description:empty { + margin: 0; +} + +/* stylelint-disable */ +#main { + margin-left: 15.625rem; + min-height: calc(100vh - 6.25rem); +} +/* stylelint-enable */ + +header { + display: block; +} + +section { + display: block; + padding: 0 30px; +} + +section header { + padding-top: 20px; +} + +section h2 { + display: inline-block; + position: relative; + z-index: 10; +} + +section h2::after { + bottom: 0; + content: ''; + display: block; + height: 10px; + position: absolute; + width: 100%; + z-index: -1; +} + +section ul { + list-style: none; + padding-left: 10px; +} + +.variation { + display: none; +} + +.signature-attributes { + font-size: 60%; + font-style: italic; + font-weight: lighter; +} + +nav { + display: block; + height: 100%; + overflow-y: auto; + position: fixed; + top: 0; + width: 250px; +} + +nav h2 { + margin: 0; + padding: 0; +} + +nav h2 img { + max-height: 100px; + max-width: 220px; + object-fit: contain; +} + +nav > h2 > a { + display: block; + font-size: 30px; + font-weight: 700; + height: 100%; + line-height: 30px !important; + margin: 0; + position: relative; + text-align: center; + text-decoration: none !important; + text-transform: uppercase; + width: 100%; + word-break: break-word; + z-index: 1; +} + +/* stylelint-disable */ +nav > h2 > a > .text::after { + bottom: -5px; + content: ''; + display: block; + height: 20px; + position: absolute; + width: 100%; + z-index: -1; +} + +/* stylelint-enable */ + +nav .search-box { + padding: 0 10px 20px; + position: relative; + z-index: 10; +} + +nav .search-box input { + border: 0; + border-radius: 5px; + font-family: 'body'; + font-size: 14px; + padding: 5px 10px; + width: 100%; +} + +.search-box .search-item-container { + border-radius: 4px; + position: absolute; + top: 35px; + width: 230px; +} + +.search-item-ul { + max-height: 150px; + overflow: auto; +} + +.search-item-ul li { + font-size: 12px; + padding: 5px 10px; + transition: 0.3s; +} + +.search-item-ul li:hover { + border-radius: 4px; +} + +.search-item-ul a:hover { + text-decoration: none; +} + +nav > h2 { + padding: 40px 10px; +} + +nav h2, +nav h3, +nav h3 a { + font-size: 18px; + margin: 0; +} + +nav h3 { + padding: 10px 10px 6px; +} + +.sidebar-list-div { + bottom: 0; + left: 0; + overflow: auto; + position: absolute; + right: 0; + top: 130px; +} + +/* If search box is there then more space is required */ + +.search-box + .sidebar-list-div { + bottom: 2rem; + top: 10.625rem; +} + +.sidebar-list-div ul, +nav ul { + font-family: 'body'; + list-style-type: none; + margin: 0; + padding: 0; +} + +nav ul a { + display: block; + font-family: 'body'; + font-size: 12px; + line-height: 18px; + padding: 0; + transition: padding 0.2s, color 0.2s, font-weight 0.2s; +} + +nav a:hover { + text-decoration: underline; +} + +.sidebar-list-div > ul { + padding-left: 10px; +} + +/* stylelint-disable */ +.sidebar-list-div > ul > li > a { + font-weight: 500; + margin: 0; + padding: 4px 10px; + word-break: break-all; +} + +.sidebar-list-div ul ul { + margin-bottom: 10px; +} + +.sidebar-list-div ul ul a { +} + +.sidebar-list-div ul ul a, +.sidebar-list-div ul ul a:active { + padding-left: 20px; +} + +/* stylelint-enable */ + +footer { + display: block; + font-size: 80%; + font-style: italic; + margin-left: 250px; + padding: 30px; +} + +.ancestors a { + text-decoration: none; +} + +.important { + font-weight: bold; +} + +.yes-def { + text-indent: -1000px; +} + +.signature { + font-family: 'code'; + font-size: 80%; +} + +.name { + font-family: 'code'; + font-size: 110%; + font-weight: bold; +} + +.name a { + font-size: 28px; +} + +.details { + margin: 0; + padding: 10px; +} + +.details .details-item-container { + display: flex; + margin: 10px 0; +} + +.details dt { + float: left; + min-width: 180px; + padding: 0 10px; +} + +.details ul { + margin: 0; +} + +.details ul { + list-style-type: none; +} + +.details ul li { + display: inline-block; + margin-right: 10px; + word-break: break-word; +} + +/* stylelint-disable */ +.details pre.prettyprint { + margin: 0; +} +/* stylelint-enable */ + +.details .object-value { + padding-top: 0; +} + +.description { + margin-bottom: 32px; +} + +.method-member-container table { + margin-top: 15px; +} + +.code-caption { + font-size: 107%; + font-style: italic; + margin: 0; +} + +.prettyprint { + border-radius: 8px; + font-size: 14px; + margin: 30px 0; + overflow: auto; + padding-top: 5px; +} + +.prettyprint.source { + width: inherit; +} + +.prettyprint code { + display: block; + font-size: 0.875rem; + line-height: 1rem; + padding: 2rem; +} + +.prettyprint > code { + padding: 30px; +} + +.prettyprint .linenums code { + padding: 0 15px; +} + +/* stylelint-disable */ +.prettyprint .linenums li:first-of-type code { + padding-top: 15px; +} + +.prettyprint code span.line { + display: inline-block; +} + +.prettyprint.linenums { + user-select: none; + user-select: none; + user-select: none; + user-select: none; +} + +.prettyprint.linenums > div { + margin-top: 1.6rem; + padding-left: 4.7rem; +} + +.prettyprint > div { + overflow: auto; +} + +.prettyprint.linenums ol { + padding-left: 0; +} + +.prettyprint.linenums li { + min-height: 18px; +} + +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * { + padding: 1px; +} +/* stylelint-enable */ + +.prettyprint.linenums li * { + user-select: text; + user-select: text; + user-select: text; + user-select: text; +} + +.params, +.props { + border-collapse: collapse; + border-radius: 8px; + border-spacing: 0; + font-size: 14px; + margin: 30px 0; + width: 100%; +} + +.params .name, +.props .name, +.name code { + font-family: 'code'; + font-size: 100%; +} + +.params td, +.params th, +.props td, +.props th { + display: table-cell; + margin: 0; + padding: 15px; + text-align: left; + vertical-align: top; +} + +.params thead tr, +.props thead tr { + font-weight: bold; +} + +/* stylelint-disable */ +.params .params thead tr, +.props .props thead tr { + font-weight: bold; +} + +.params td.description > p:first-child, +.props td.description > p:first-child { + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +dl.param-type { + margin-bottom: 30px; + padding-bottom: 30px; +} + +/* stylelint-enable */ + +.param-type dt, +.param-type dd { + display: inline-block; +} + +.param-type dd { + font-family: 'code'; + font-size: 80%; +} + +/* navicon button */ + +.navicon-button { + cursor: pointer; + display: none; + padding: 20px 10px; + position: relative; + transition: 0.25s; + user-select: none; +} + +.navicon-button .navicon::before, +.navicon-button .navicon::after { + transition: 0.25s; +} + +.navicon-button:hover { + opacity: 1; + transition: 0.5s; +} + +.navicon-button:hover .navicon::before, +.navicon-button:hover .navicon::after { + transition: 0.25s; +} + +.navicon-button:hover .navicon::before { + top: 0.625rem; +} + +.navicon-button:hover .navicon::after { + top: -0.625rem; +} + +/* navicon */ + +.navicon { + border-radius: 2.5rem; + height: 0.125rem; + position: relative; + transition: 0.3s; + width: 2em; +} + +.navicon::before, +.navicon::after { + border-radius: 1rem; + content: ''; + display: block; + height: 0.125rem; + position: absolute; + transition: 0.3s 0.25s; + width: 2rem; + z-index: -1; +} + +.navicon::before { + top: 0.5rem; +} + +.navicon::after { + top: -0.5rem; +} + +/* open */ + +.nav-trigger:checked + label:not(.steps) .navicon::before, +.nav-trigger:checked + label:not(.steps) .navicon::after { + top: 0 !important; +} + +.nav-trigger:checked + label .navicon::before, +.nav-trigger:checked + label .navicon::after { + transition: 0.5s; +} + +/* stylelint-disable */ +.nav-trigger:checked + label.plus .navicon::before, +.nav-trigger:checked + label.x .navicon::before { + transform: rotate(-45deg); +} + +.nav-trigger:checked + label .navicon { + background: transparent; +} + +.nav-trigger:checked + label.plus .navicon::after, +.nav-trigger:checked + label.x .navicon::after { + transform: rotate(45deg); +} + +.nav-trigger:checked + label.plus { + transform: rotate(45deg); +} + +.nav-trigger:checked ~ nav { + left: 0 !important; +} + +.nav-trigger:checked ~ .overlay { + display: block; +} + +/* stylelint-enable */ + +.nav-trigger { + clip: rect(0, 0, 0, 0); + position: fixed; + top: 0; +} + +.overlay { + bottom: 0; + display: none; + height: 100%; + left: 0; + position: fixed; + right: 0; + top: 0; + width: 100%; + z-index: 1; +} + +@media only screen and (max-width: 42rem) { + /* Media query */ + + body { + overflow-x: hidden; + } + + nav { + bottom: 0; + left: -250px; + right: 0; + top: 0; + transition: left 0.2s; + z-index: 1000; + } + + .navicon-button { + border-radius: 10px; + display: inline-block; + position: fixed; + right: 30px; + top: 30px; + z-index: 1000; + } + + /* stylelint-disable */ + #main { + margin-left: 0; + min-width: 360px; + padding: 0 25px; + width: 100%; + } + + #main h1.page-title { + margin: 60px 0 10px; + } + + #main section { + padding: 0; + } + /* stylelint-enable */ + + footer { + margin-left: 0; + } +} + +/* Extra */ + +.flex { + display: flex; +} + +.flex-col { + flex-direction: column; +} + +.overflow-auto { + overflow: auto; +} + +.w-100 { + width: 100%; +} + +.mt-20 { + margin-top: 20px; +} + +/* End */ diff --git a/docs/modern-async/1.0.4/styles/third-party/ionicons.min.css b/docs/modern-async/1.0.4/styles/third-party/ionicons.min.css new file mode 100644 index 0000000..040a60d --- /dev/null +++ b/docs/modern-async/1.0.4/styles/third-party/ionicons.min.css @@ -0,0 +1,11 @@ +@charset "UTF-8";/*! + Ionicons, v2.0.1 + Created by Ben Sperry for the Ionic Framework, http://ionicons.com/ + https://twitter.com/benjsperry https://twitter.com/ionicframework + MIT License: https://github.com/driftyco/ionicons + + Android-style icons originally built by Google’s + Material Design Icons: https://github.com/google/material-design-icons + used under CC BY http://creativecommons.org/licenses/by/4.0/ + Modified icons to fit ionicon’s grid from original. +*/@font-face{font-family:"Ionicons";src:url("../fonts/ionicons.eot?v=2.0.1");src:url("../fonts/ionicons.eot?v=2.0.1#iefix") format("embedded-opentype"),url("../fonts/ionicons.ttf?v=2.0.1") format("truetype"),url("../fonts/ionicons.woff?v=2.0.1") format("woff"),url("../fonts/ionicons.svg?v=2.0.1#Ionicons") format("svg");font-weight:normal;font-style:normal}.ion,.ionicons,.ion-alert:before,.ion-alert-circled:before,.ion-android-add:before,.ion-android-add-circle:before,.ion-android-alarm-clock:before,.ion-android-alert:before,.ion-android-apps:before,.ion-android-archive:before,.ion-android-arrow-back:before,.ion-android-arrow-down:before,.ion-android-arrow-dropdown:before,.ion-android-arrow-dropdown-circle:before,.ion-android-arrow-dropleft:before,.ion-android-arrow-dropleft-circle:before,.ion-android-arrow-dropright:before,.ion-android-arrow-dropright-circle:before,.ion-android-arrow-dropup:before,.ion-android-arrow-dropup-circle:before,.ion-android-arrow-forward:before,.ion-android-arrow-up:before,.ion-android-attach:before,.ion-android-bar:before,.ion-android-bicycle:before,.ion-android-boat:before,.ion-android-bookmark:before,.ion-android-bulb:before,.ion-android-bus:before,.ion-android-calendar:before,.ion-android-call:before,.ion-android-camera:before,.ion-android-cancel:before,.ion-android-car:before,.ion-android-cart:before,.ion-android-chat:before,.ion-android-checkbox:before,.ion-android-checkbox-blank:before,.ion-android-checkbox-outline:before,.ion-android-checkbox-outline-blank:before,.ion-android-checkmark-circle:before,.ion-android-clipboard:before,.ion-android-close:before,.ion-android-cloud:before,.ion-android-cloud-circle:before,.ion-android-cloud-done:before,.ion-android-cloud-outline:before,.ion-android-color-palette:before,.ion-android-compass:before,.ion-android-contact:before,.ion-android-contacts:before,.ion-android-contract:before,.ion-android-create:before,.ion-android-delete:before,.ion-android-desktop:before,.ion-android-document:before,.ion-android-done:before,.ion-android-done-all:before,.ion-android-download:before,.ion-android-drafts:before,.ion-android-exit:before,.ion-android-expand:before,.ion-android-favorite:before,.ion-android-favorite-outline:before,.ion-android-film:before,.ion-android-folder:before,.ion-android-folder-open:before,.ion-android-funnel:before,.ion-android-globe:before,.ion-android-hand:before,.ion-android-hangout:before,.ion-android-happy:before,.ion-android-home:before,.ion-android-image:before,.ion-android-laptop:before,.ion-android-list:before,.ion-android-locate:before,.ion-android-lock:before,.ion-android-mail:before,.ion-android-map:before,.ion-android-menu:before,.ion-android-microphone:before,.ion-android-microphone-off:before,.ion-android-more-horizontal:before,.ion-android-more-vertical:before,.ion-android-navigate:before,.ion-android-notifications:before,.ion-android-notifications-none:before,.ion-android-notifications-off:before,.ion-android-open:before,.ion-android-options:before,.ion-android-people:before,.ion-android-person:before,.ion-android-person-add:before,.ion-android-phone-landscape:before,.ion-android-phone-portrait:before,.ion-android-pin:before,.ion-android-plane:before,.ion-android-playstore:before,.ion-android-print:before,.ion-android-radio-button-off:before,.ion-android-radio-button-on:before,.ion-android-refresh:before,.ion-android-remove:before,.ion-android-remove-circle:before,.ion-android-restaurant:before,.ion-android-sad:before,.ion-android-search:before,.ion-android-send:before,.ion-android-settings:before,.ion-android-share:before,.ion-android-share-alt:before,.ion-android-star:before,.ion-android-star-half:before,.ion-android-star-outline:before,.ion-android-stopwatch:before,.ion-android-subway:before,.ion-android-sunny:before,.ion-android-sync:before,.ion-android-textsms:before,.ion-android-time:before,.ion-android-train:before,.ion-android-unlock:before,.ion-android-upload:before,.ion-android-volume-down:before,.ion-android-volume-mute:before,.ion-android-volume-off:before,.ion-android-volume-up:before,.ion-android-walk:before,.ion-android-warning:before,.ion-android-watch:before,.ion-android-wifi:before,.ion-aperture:before,.ion-archive:before,.ion-arrow-down-a:before,.ion-arrow-down-b:before,.ion-arrow-down-c:before,.ion-arrow-expand:before,.ion-arrow-graph-down-left:before,.ion-arrow-graph-down-right:before,.ion-arrow-graph-up-left:before,.ion-arrow-graph-up-right:before,.ion-arrow-left-a:before,.ion-arrow-left-b:before,.ion-arrow-left-c:before,.ion-arrow-move:before,.ion-arrow-resize:before,.ion-arrow-return-left:before,.ion-arrow-return-right:before,.ion-arrow-right-a:before,.ion-arrow-right-b:before,.ion-arrow-right-c:before,.ion-arrow-shrink:before,.ion-arrow-swap:before,.ion-arrow-up-a:before,.ion-arrow-up-b:before,.ion-arrow-up-c:before,.ion-asterisk:before,.ion-at:before,.ion-backspace:before,.ion-backspace-outline:before,.ion-bag:before,.ion-battery-charging:before,.ion-battery-empty:before,.ion-battery-full:before,.ion-battery-half:before,.ion-battery-low:before,.ion-beaker:before,.ion-beer:before,.ion-bluetooth:before,.ion-bonfire:before,.ion-bookmark:before,.ion-bowtie:before,.ion-briefcase:before,.ion-bug:before,.ion-calculator:before,.ion-calendar:before,.ion-camera:before,.ion-card:before,.ion-cash:before,.ion-chatbox:before,.ion-chatbox-working:before,.ion-chatboxes:before,.ion-chatbubble:before,.ion-chatbubble-working:before,.ion-chatbubbles:before,.ion-checkmark:before,.ion-checkmark-circled:before,.ion-checkmark-round:before,.ion-chevron-down:before,.ion-chevron-left:before,.ion-chevron-right:before,.ion-chevron-up:before,.ion-clipboard:before,.ion-clock:before,.ion-close:before,.ion-close-circled:before,.ion-close-round:before,.ion-closed-captioning:before,.ion-cloud:before,.ion-code:before,.ion-code-download:before,.ion-code-working:before,.ion-coffee:before,.ion-compass:before,.ion-compose:before,.ion-connection-bars:before,.ion-contrast:before,.ion-crop:before,.ion-cube:before,.ion-disc:before,.ion-document:before,.ion-document-text:before,.ion-drag:before,.ion-earth:before,.ion-easel:before,.ion-edit:before,.ion-egg:before,.ion-eject:before,.ion-email:before,.ion-email-unread:before,.ion-erlenmeyer-flask:before,.ion-erlenmeyer-flask-bubbles:before,.ion-eye:before,.ion-eye-disabled:before,.ion-female:before,.ion-filing:before,.ion-film-marker:before,.ion-fireball:before,.ion-flag:before,.ion-flame:before,.ion-flash:before,.ion-flash-off:before,.ion-folder:before,.ion-fork:before,.ion-fork-repo:before,.ion-forward:before,.ion-funnel:before,.ion-gear-a:before,.ion-gear-b:before,.ion-grid:before,.ion-hammer:before,.ion-happy:before,.ion-happy-outline:before,.ion-headphone:before,.ion-heart:before,.ion-heart-broken:before,.ion-help:before,.ion-help-buoy:before,.ion-help-circled:before,.ion-home:before,.ion-icecream:before,.ion-image:before,.ion-images:before,.ion-information:before,.ion-information-circled:before,.ion-ionic:before,.ion-ios-alarm:before,.ion-ios-alarm-outline:before,.ion-ios-albums:before,.ion-ios-albums-outline:before,.ion-ios-americanfootball:before,.ion-ios-americanfootball-outline:before,.ion-ios-analytics:before,.ion-ios-analytics-outline:before,.ion-ios-arrow-back:before,.ion-ios-arrow-down:before,.ion-ios-arrow-forward:before,.ion-ios-arrow-left:before,.ion-ios-arrow-right:before,.ion-ios-arrow-thin-down:before,.ion-ios-arrow-thin-left:before,.ion-ios-arrow-thin-right:before,.ion-ios-arrow-thin-up:before,.ion-ios-arrow-up:before,.ion-ios-at:before,.ion-ios-at-outline:before,.ion-ios-barcode:before,.ion-ios-barcode-outline:before,.ion-ios-baseball:before,.ion-ios-baseball-outline:before,.ion-ios-basketball:before,.ion-ios-basketball-outline:before,.ion-ios-bell:before,.ion-ios-bell-outline:before,.ion-ios-body:before,.ion-ios-body-outline:before,.ion-ios-bolt:before,.ion-ios-bolt-outline:before,.ion-ios-book:before,.ion-ios-book-outline:before,.ion-ios-bookmarks:before,.ion-ios-bookmarks-outline:before,.ion-ios-box:before,.ion-ios-box-outline:before,.ion-ios-briefcase:before,.ion-ios-briefcase-outline:before,.ion-ios-browsers:before,.ion-ios-browsers-outline:before,.ion-ios-calculator:before,.ion-ios-calculator-outline:before,.ion-ios-calendar:before,.ion-ios-calendar-outline:before,.ion-ios-camera:before,.ion-ios-camera-outline:before,.ion-ios-cart:before,.ion-ios-cart-outline:before,.ion-ios-chatboxes:before,.ion-ios-chatboxes-outline:before,.ion-ios-chatbubble:before,.ion-ios-chatbubble-outline:before,.ion-ios-checkmark:before,.ion-ios-checkmark-empty:before,.ion-ios-checkmark-outline:before,.ion-ios-circle-filled:before,.ion-ios-circle-outline:before,.ion-ios-clock:before,.ion-ios-clock-outline:before,.ion-ios-close:before,.ion-ios-close-empty:before,.ion-ios-close-outline:before,.ion-ios-cloud:before,.ion-ios-cloud-download:before,.ion-ios-cloud-download-outline:before,.ion-ios-cloud-outline:before,.ion-ios-cloud-upload:before,.ion-ios-cloud-upload-outline:before,.ion-ios-cloudy:before,.ion-ios-cloudy-night:before,.ion-ios-cloudy-night-outline:before,.ion-ios-cloudy-outline:before,.ion-ios-cog:before,.ion-ios-cog-outline:before,.ion-ios-color-filter:before,.ion-ios-color-filter-outline:before,.ion-ios-color-wand:before,.ion-ios-color-wand-outline:before,.ion-ios-compose:before,.ion-ios-compose-outline:before,.ion-ios-contact:before,.ion-ios-contact-outline:before,.ion-ios-copy:before,.ion-ios-copy-outline:before,.ion-ios-crop:before,.ion-ios-crop-strong:before,.ion-ios-download:before,.ion-ios-download-outline:before,.ion-ios-drag:before,.ion-ios-email:before,.ion-ios-email-outline:before,.ion-ios-eye:before,.ion-ios-eye-outline:before,.ion-ios-fastforward:before,.ion-ios-fastforward-outline:before,.ion-ios-filing:before,.ion-ios-filing-outline:before,.ion-ios-film:before,.ion-ios-film-outline:before,.ion-ios-flag:before,.ion-ios-flag-outline:before,.ion-ios-flame:before,.ion-ios-flame-outline:before,.ion-ios-flask:before,.ion-ios-flask-outline:before,.ion-ios-flower:before,.ion-ios-flower-outline:before,.ion-ios-folder:before,.ion-ios-folder-outline:before,.ion-ios-football:before,.ion-ios-football-outline:before,.ion-ios-game-controller-a:before,.ion-ios-game-controller-a-outline:before,.ion-ios-game-controller-b:before,.ion-ios-game-controller-b-outline:before,.ion-ios-gear:before,.ion-ios-gear-outline:before,.ion-ios-glasses:before,.ion-ios-glasses-outline:before,.ion-ios-grid-view:before,.ion-ios-grid-view-outline:before,.ion-ios-heart:before,.ion-ios-heart-outline:before,.ion-ios-help:before,.ion-ios-help-empty:before,.ion-ios-help-outline:before,.ion-ios-home:before,.ion-ios-home-outline:before,.ion-ios-infinite:before,.ion-ios-infinite-outline:before,.ion-ios-information:before,.ion-ios-information-empty:before,.ion-ios-information-outline:before,.ion-ios-ionic-outline:before,.ion-ios-keypad:before,.ion-ios-keypad-outline:before,.ion-ios-lightbulb:before,.ion-ios-lightbulb-outline:before,.ion-ios-list:before,.ion-ios-list-outline:before,.ion-ios-location:before,.ion-ios-location-outline:before,.ion-ios-locked:before,.ion-ios-locked-outline:before,.ion-ios-loop:before,.ion-ios-loop-strong:before,.ion-ios-medical:before,.ion-ios-medical-outline:before,.ion-ios-medkit:before,.ion-ios-medkit-outline:before,.ion-ios-mic:before,.ion-ios-mic-off:before,.ion-ios-mic-outline:before,.ion-ios-minus:before,.ion-ios-minus-empty:before,.ion-ios-minus-outline:before,.ion-ios-monitor:before,.ion-ios-monitor-outline:before,.ion-ios-moon:before,.ion-ios-moon-outline:before,.ion-ios-more:before,.ion-ios-more-outline:before,.ion-ios-musical-note:before,.ion-ios-musical-notes:before,.ion-ios-navigate:before,.ion-ios-navigate-outline:before,.ion-ios-nutrition:before,.ion-ios-nutrition-outline:before,.ion-ios-paper:before,.ion-ios-paper-outline:before,.ion-ios-paperplane:before,.ion-ios-paperplane-outline:before,.ion-ios-partlysunny:before,.ion-ios-partlysunny-outline:before,.ion-ios-pause:before,.ion-ios-pause-outline:before,.ion-ios-paw:before,.ion-ios-paw-outline:before,.ion-ios-people:before,.ion-ios-people-outline:before,.ion-ios-person:before,.ion-ios-person-outline:before,.ion-ios-personadd:before,.ion-ios-personadd-outline:before,.ion-ios-photos:before,.ion-ios-photos-outline:before,.ion-ios-pie:before,.ion-ios-pie-outline:before,.ion-ios-pint:before,.ion-ios-pint-outline:before,.ion-ios-play:before,.ion-ios-play-outline:before,.ion-ios-plus:before,.ion-ios-plus-empty:before,.ion-ios-plus-outline:before,.ion-ios-pricetag:before,.ion-ios-pricetag-outline:before,.ion-ios-pricetags:before,.ion-ios-pricetags-outline:before,.ion-ios-printer:before,.ion-ios-printer-outline:before,.ion-ios-pulse:before,.ion-ios-pulse-strong:before,.ion-ios-rainy:before,.ion-ios-rainy-outline:before,.ion-ios-recording:before,.ion-ios-recording-outline:before,.ion-ios-redo:before,.ion-ios-redo-outline:before,.ion-ios-refresh:before,.ion-ios-refresh-empty:before,.ion-ios-refresh-outline:before,.ion-ios-reload:before,.ion-ios-reverse-camera:before,.ion-ios-reverse-camera-outline:before,.ion-ios-rewind:before,.ion-ios-rewind-outline:before,.ion-ios-rose:before,.ion-ios-rose-outline:before,.ion-ios-search:before,.ion-ios-search-strong:before,.ion-ios-settings:before,.ion-ios-settings-strong:before,.ion-ios-shuffle:before,.ion-ios-shuffle-strong:before,.ion-ios-skipbackward:before,.ion-ios-skipbackward-outline:before,.ion-ios-skipforward:before,.ion-ios-skipforward-outline:before,.ion-ios-snowy:before,.ion-ios-speedometer:before,.ion-ios-speedometer-outline:before,.ion-ios-star:before,.ion-ios-star-half:before,.ion-ios-star-outline:before,.ion-ios-stopwatch:before,.ion-ios-stopwatch-outline:before,.ion-ios-sunny:before,.ion-ios-sunny-outline:before,.ion-ios-telephone:before,.ion-ios-telephone-outline:before,.ion-ios-tennisball:before,.ion-ios-tennisball-outline:before,.ion-ios-thunderstorm:before,.ion-ios-thunderstorm-outline:before,.ion-ios-time:before,.ion-ios-time-outline:before,.ion-ios-timer:before,.ion-ios-timer-outline:before,.ion-ios-toggle:before,.ion-ios-toggle-outline:before,.ion-ios-trash:before,.ion-ios-trash-outline:before,.ion-ios-undo:before,.ion-ios-undo-outline:before,.ion-ios-unlocked:before,.ion-ios-unlocked-outline:before,.ion-ios-upload:before,.ion-ios-upload-outline:before,.ion-ios-videocam:before,.ion-ios-videocam-outline:before,.ion-ios-volume-high:before,.ion-ios-volume-low:before,.ion-ios-wineglass:before,.ion-ios-wineglass-outline:before,.ion-ios-world:before,.ion-ios-world-outline:before,.ion-ipad:before,.ion-iphone:before,.ion-ipod:before,.ion-jet:before,.ion-key:before,.ion-knife:before,.ion-laptop:before,.ion-leaf:before,.ion-levels:before,.ion-lightbulb:before,.ion-link:before,.ion-load-a:before,.ion-load-b:before,.ion-load-c:before,.ion-load-d:before,.ion-location:before,.ion-lock-combination:before,.ion-locked:before,.ion-log-in:before,.ion-log-out:before,.ion-loop:before,.ion-magnet:before,.ion-male:before,.ion-man:before,.ion-map:before,.ion-medkit:before,.ion-merge:before,.ion-mic-a:before,.ion-mic-b:before,.ion-mic-c:before,.ion-minus:before,.ion-minus-circled:before,.ion-minus-round:before,.ion-model-s:before,.ion-monitor:before,.ion-more:before,.ion-mouse:before,.ion-music-note:before,.ion-navicon:before,.ion-navicon-round:before,.ion-navigate:before,.ion-network:before,.ion-no-smoking:before,.ion-nuclear:before,.ion-outlet:before,.ion-paintbrush:before,.ion-paintbucket:before,.ion-paper-airplane:before,.ion-paperclip:before,.ion-pause:before,.ion-person:before,.ion-person-add:before,.ion-person-stalker:before,.ion-pie-graph:before,.ion-pin:before,.ion-pinpoint:before,.ion-pizza:before,.ion-plane:before,.ion-planet:before,.ion-play:before,.ion-playstation:before,.ion-plus:before,.ion-plus-circled:before,.ion-plus-round:before,.ion-podium:before,.ion-pound:before,.ion-power:before,.ion-pricetag:before,.ion-pricetags:before,.ion-printer:before,.ion-pull-request:before,.ion-qr-scanner:before,.ion-quote:before,.ion-radio-waves:before,.ion-record:before,.ion-refresh:before,.ion-reply:before,.ion-reply-all:before,.ion-ribbon-a:before,.ion-ribbon-b:before,.ion-sad:before,.ion-sad-outline:before,.ion-scissors:before,.ion-search:before,.ion-settings:before,.ion-share:before,.ion-shuffle:before,.ion-skip-backward:before,.ion-skip-forward:before,.ion-social-android:before,.ion-social-android-outline:before,.ion-social-angular:before,.ion-social-angular-outline:before,.ion-social-apple:before,.ion-social-apple-outline:before,.ion-social-bitcoin:before,.ion-social-bitcoin-outline:before,.ion-social-buffer:before,.ion-social-buffer-outline:before,.ion-social-chrome:before,.ion-social-chrome-outline:before,.ion-social-codepen:before,.ion-social-codepen-outline:before,.ion-social-css3:before,.ion-social-css3-outline:before,.ion-social-designernews:before,.ion-social-designernews-outline:before,.ion-social-dribbble:before,.ion-social-dribbble-outline:before,.ion-social-dropbox:before,.ion-social-dropbox-outline:before,.ion-social-euro:before,.ion-social-euro-outline:before,.ion-social-facebook:before,.ion-social-facebook-outline:before,.ion-social-foursquare:before,.ion-social-foursquare-outline:before,.ion-social-freebsd-devil:before,.ion-social-github:before,.ion-social-github-outline:before,.ion-social-google:before,.ion-social-google-outline:before,.ion-social-googleplus:before,.ion-social-googleplus-outline:before,.ion-social-hackernews:before,.ion-social-hackernews-outline:before,.ion-social-html5:before,.ion-social-html5-outline:before,.ion-social-instagram:before,.ion-social-instagram-outline:before,.ion-social-javascript:before,.ion-social-javascript-outline:before,.ion-social-linkedin:before,.ion-social-linkedin-outline:before,.ion-social-markdown:before,.ion-social-nodejs:before,.ion-social-octocat:before,.ion-social-pinterest:before,.ion-social-pinterest-outline:before,.ion-social-python:before,.ion-social-reddit:before,.ion-social-reddit-outline:before,.ion-social-rss:before,.ion-social-rss-outline:before,.ion-social-sass:before,.ion-social-skype:before,.ion-social-skype-outline:before,.ion-social-snapchat:before,.ion-social-snapchat-outline:before,.ion-social-tumblr:before,.ion-social-tumblr-outline:before,.ion-social-tux:before,.ion-social-twitch:before,.ion-social-twitch-outline:before,.ion-social-twitter:before,.ion-social-twitter-outline:before,.ion-social-usd:before,.ion-social-usd-outline:before,.ion-social-vimeo:before,.ion-social-vimeo-outline:before,.ion-social-whatsapp:before,.ion-social-whatsapp-outline:before,.ion-social-windows:before,.ion-social-windows-outline:before,.ion-social-wordpress:before,.ion-social-wordpress-outline:before,.ion-social-yahoo:before,.ion-social-yahoo-outline:before,.ion-social-yen:before,.ion-social-yen-outline:before,.ion-social-youtube:before,.ion-social-youtube-outline:before,.ion-soup-can:before,.ion-soup-can-outline:before,.ion-speakerphone:before,.ion-speedometer:before,.ion-spoon:before,.ion-star:before,.ion-stats-bars:before,.ion-steam:before,.ion-stop:before,.ion-thermometer:before,.ion-thumbsdown:before,.ion-thumbsup:before,.ion-toggle:before,.ion-toggle-filled:before,.ion-transgender:before,.ion-trash-a:before,.ion-trash-b:before,.ion-trophy:before,.ion-tshirt:before,.ion-tshirt-outline:before,.ion-umbrella:before,.ion-university:before,.ion-unlocked:before,.ion-upload:before,.ion-usb:before,.ion-videocamera:before,.ion-volume-high:before,.ion-volume-low:before,.ion-volume-medium:before,.ion-volume-mute:before,.ion-wand:before,.ion-waterdrop:before,.ion-wifi:before,.ion-wineglass:before,.ion-woman:before,.ion-wrench:before,.ion-xbox:before{display:inline-block;font-family:"Ionicons";speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;text-rendering:auto;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ion-alert:before{content:"\f101"}.ion-alert-circled:before{content:"\f100"}.ion-android-add:before{content:"\f2c7"}.ion-android-add-circle:before{content:"\f359"}.ion-android-alarm-clock:before{content:"\f35a"}.ion-android-alert:before{content:"\f35b"}.ion-android-apps:before{content:"\f35c"}.ion-android-archive:before{content:"\f2c9"}.ion-android-arrow-back:before{content:"\f2ca"}.ion-android-arrow-down:before{content:"\f35d"}.ion-android-arrow-dropdown:before{content:"\f35f"}.ion-android-arrow-dropdown-circle:before{content:"\f35e"}.ion-android-arrow-dropleft:before{content:"\f361"}.ion-android-arrow-dropleft-circle:before{content:"\f360"}.ion-android-arrow-dropright:before{content:"\f363"}.ion-android-arrow-dropright-circle:before{content:"\f362"}.ion-android-arrow-dropup:before{content:"\f365"}.ion-android-arrow-dropup-circle:before{content:"\f364"}.ion-android-arrow-forward:before{content:"\f30f"}.ion-android-arrow-up:before{content:"\f366"}.ion-android-attach:before{content:"\f367"}.ion-android-bar:before{content:"\f368"}.ion-android-bicycle:before{content:"\f369"}.ion-android-boat:before{content:"\f36a"}.ion-android-bookmark:before{content:"\f36b"}.ion-android-bulb:before{content:"\f36c"}.ion-android-bus:before{content:"\f36d"}.ion-android-calendar:before{content:"\f2d1"}.ion-android-call:before{content:"\f2d2"}.ion-android-camera:before{content:"\f2d3"}.ion-android-cancel:before{content:"\f36e"}.ion-android-car:before{content:"\f36f"}.ion-android-cart:before{content:"\f370"}.ion-android-chat:before{content:"\f2d4"}.ion-android-checkbox:before{content:"\f374"}.ion-android-checkbox-blank:before{content:"\f371"}.ion-android-checkbox-outline:before{content:"\f373"}.ion-android-checkbox-outline-blank:before{content:"\f372"}.ion-android-checkmark-circle:before{content:"\f375"}.ion-android-clipboard:before{content:"\f376"}.ion-android-close:before{content:"\f2d7"}.ion-android-cloud:before{content:"\f37a"}.ion-android-cloud-circle:before{content:"\f377"}.ion-android-cloud-done:before{content:"\f378"}.ion-android-cloud-outline:before{content:"\f379"}.ion-android-color-palette:before{content:"\f37b"}.ion-android-compass:before{content:"\f37c"}.ion-android-contact:before{content:"\f2d8"}.ion-android-contacts:before{content:"\f2d9"}.ion-android-contract:before{content:"\f37d"}.ion-android-create:before{content:"\f37e"}.ion-android-delete:before{content:"\f37f"}.ion-android-desktop:before{content:"\f380"}.ion-android-document:before{content:"\f381"}.ion-android-done:before{content:"\f383"}.ion-android-done-all:before{content:"\f382"}.ion-android-download:before{content:"\f2dd"}.ion-android-drafts:before{content:"\f384"}.ion-android-exit:before{content:"\f385"}.ion-android-expand:before{content:"\f386"}.ion-android-favorite:before{content:"\f388"}.ion-android-favorite-outline:before{content:"\f387"}.ion-android-film:before{content:"\f389"}.ion-android-folder:before{content:"\f2e0"}.ion-android-folder-open:before{content:"\f38a"}.ion-android-funnel:before{content:"\f38b"}.ion-android-globe:before{content:"\f38c"}.ion-android-hand:before{content:"\f2e3"}.ion-android-hangout:before{content:"\f38d"}.ion-android-happy:before{content:"\f38e"}.ion-android-home:before{content:"\f38f"}.ion-android-image:before{content:"\f2e4"}.ion-android-laptop:before{content:"\f390"}.ion-android-list:before{content:"\f391"}.ion-android-locate:before{content:"\f2e9"}.ion-android-lock:before{content:"\f392"}.ion-android-mail:before{content:"\f2eb"}.ion-android-map:before{content:"\f393"}.ion-android-menu:before{content:"\f394"}.ion-android-microphone:before{content:"\f2ec"}.ion-android-microphone-off:before{content:"\f395"}.ion-android-more-horizontal:before{content:"\f396"}.ion-android-more-vertical:before{content:"\f397"}.ion-android-navigate:before{content:"\f398"}.ion-android-notifications:before{content:"\f39b"}.ion-android-notifications-none:before{content:"\f399"}.ion-android-notifications-off:before{content:"\f39a"}.ion-android-open:before{content:"\f39c"}.ion-android-options:before{content:"\f39d"}.ion-android-people:before{content:"\f39e"}.ion-android-person:before{content:"\f3a0"}.ion-android-person-add:before{content:"\f39f"}.ion-android-phone-landscape:before{content:"\f3a1"}.ion-android-phone-portrait:before{content:"\f3a2"}.ion-android-pin:before{content:"\f3a3"}.ion-android-plane:before{content:"\f3a4"}.ion-android-playstore:before{content:"\f2f0"}.ion-android-print:before{content:"\f3a5"}.ion-android-radio-button-off:before{content:"\f3a6"}.ion-android-radio-button-on:before{content:"\f3a7"}.ion-android-refresh:before{content:"\f3a8"}.ion-android-remove:before{content:"\f2f4"}.ion-android-remove-circle:before{content:"\f3a9"}.ion-android-restaurant:before{content:"\f3aa"}.ion-android-sad:before{content:"\f3ab"}.ion-android-search:before{content:"\f2f5"}.ion-android-send:before{content:"\f2f6"}.ion-android-settings:before{content:"\f2f7"}.ion-android-share:before{content:"\f2f8"}.ion-android-share-alt:before{content:"\f3ac"}.ion-android-star:before{content:"\f2fc"}.ion-android-star-half:before{content:"\f3ad"}.ion-android-star-outline:before{content:"\f3ae"}.ion-android-stopwatch:before{content:"\f2fd"}.ion-android-subway:before{content:"\f3af"}.ion-android-sunny:before{content:"\f3b0"}.ion-android-sync:before{content:"\f3b1"}.ion-android-textsms:before{content:"\f3b2"}.ion-android-time:before{content:"\f3b3"}.ion-android-train:before{content:"\f3b4"}.ion-android-unlock:before{content:"\f3b5"}.ion-android-upload:before{content:"\f3b6"}.ion-android-volume-down:before{content:"\f3b7"}.ion-android-volume-mute:before{content:"\f3b8"}.ion-android-volume-off:before{content:"\f3b9"}.ion-android-volume-up:before{content:"\f3ba"}.ion-android-walk:before{content:"\f3bb"}.ion-android-warning:before{content:"\f3bc"}.ion-android-watch:before{content:"\f3bd"}.ion-android-wifi:before{content:"\f305"}.ion-aperture:before{content:"\f313"}.ion-archive:before{content:"\f102"}.ion-arrow-down-a:before{content:"\f103"}.ion-arrow-down-b:before{content:"\f104"}.ion-arrow-down-c:before{content:"\f105"}.ion-arrow-expand:before{content:"\f25e"}.ion-arrow-graph-down-left:before{content:"\f25f"}.ion-arrow-graph-down-right:before{content:"\f260"}.ion-arrow-graph-up-left:before{content:"\f261"}.ion-arrow-graph-up-right:before{content:"\f262"}.ion-arrow-left-a:before{content:"\f106"}.ion-arrow-left-b:before{content:"\f107"}.ion-arrow-left-c:before{content:"\f108"}.ion-arrow-move:before{content:"\f263"}.ion-arrow-resize:before{content:"\f264"}.ion-arrow-return-left:before{content:"\f265"}.ion-arrow-return-right:before{content:"\f266"}.ion-arrow-right-a:before{content:"\f109"}.ion-arrow-right-b:before{content:"\f10a"}.ion-arrow-right-c:before{content:"\f10b"}.ion-arrow-shrink:before{content:"\f267"}.ion-arrow-swap:before{content:"\f268"}.ion-arrow-up-a:before{content:"\f10c"}.ion-arrow-up-b:before{content:"\f10d"}.ion-arrow-up-c:before{content:"\f10e"}.ion-asterisk:before{content:"\f314"}.ion-at:before{content:"\f10f"}.ion-backspace:before{content:"\f3bf"}.ion-backspace-outline:before{content:"\f3be"}.ion-bag:before{content:"\f110"}.ion-battery-charging:before{content:"\f111"}.ion-battery-empty:before{content:"\f112"}.ion-battery-full:before{content:"\f113"}.ion-battery-half:before{content:"\f114"}.ion-battery-low:before{content:"\f115"}.ion-beaker:before{content:"\f269"}.ion-beer:before{content:"\f26a"}.ion-bluetooth:before{content:"\f116"}.ion-bonfire:before{content:"\f315"}.ion-bookmark:before{content:"\f26b"}.ion-bowtie:before{content:"\f3c0"}.ion-briefcase:before{content:"\f26c"}.ion-bug:before{content:"\f2be"}.ion-calculator:before{content:"\f26d"}.ion-calendar:before{content:"\f117"}.ion-camera:before{content:"\f118"}.ion-card:before{content:"\f119"}.ion-cash:before{content:"\f316"}.ion-chatbox:before{content:"\f11b"}.ion-chatbox-working:before{content:"\f11a"}.ion-chatboxes:before{content:"\f11c"}.ion-chatbubble:before{content:"\f11e"}.ion-chatbubble-working:before{content:"\f11d"}.ion-chatbubbles:before{content:"\f11f"}.ion-checkmark:before{content:"\f122"}.ion-checkmark-circled:before{content:"\f120"}.ion-checkmark-round:before{content:"\f121"}.ion-chevron-down:before{content:"\f123"}.ion-chevron-left:before{content:"\f124"}.ion-chevron-right:before{content:"\f125"}.ion-chevron-up:before{content:"\f126"}.ion-clipboard:before{content:"\f127"}.ion-clock:before{content:"\f26e"}.ion-close:before{content:"\f12a"}.ion-close-circled:before{content:"\f128"}.ion-close-round:before{content:"\f129"}.ion-closed-captioning:before{content:"\f317"}.ion-cloud:before{content:"\f12b"}.ion-code:before{content:"\f271"}.ion-code-download:before{content:"\f26f"}.ion-code-working:before{content:"\f270"}.ion-coffee:before{content:"\f272"}.ion-compass:before{content:"\f273"}.ion-compose:before{content:"\f12c"}.ion-connection-bars:before{content:"\f274"}.ion-contrast:before{content:"\f275"}.ion-crop:before{content:"\f3c1"}.ion-cube:before{content:"\f318"}.ion-disc:before{content:"\f12d"}.ion-document:before{content:"\f12f"}.ion-document-text:before{content:"\f12e"}.ion-drag:before{content:"\f130"}.ion-earth:before{content:"\f276"}.ion-easel:before{content:"\f3c2"}.ion-edit:before{content:"\f2bf"}.ion-egg:before{content:"\f277"}.ion-eject:before{content:"\f131"}.ion-email:before{content:"\f132"}.ion-email-unread:before{content:"\f3c3"}.ion-erlenmeyer-flask:before{content:"\f3c5"}.ion-erlenmeyer-flask-bubbles:before{content:"\f3c4"}.ion-eye:before{content:"\f133"}.ion-eye-disabled:before{content:"\f306"}.ion-female:before{content:"\f278"}.ion-filing:before{content:"\f134"}.ion-film-marker:before{content:"\f135"}.ion-fireball:before{content:"\f319"}.ion-flag:before{content:"\f279"}.ion-flame:before{content:"\f31a"}.ion-flash:before{content:"\f137"}.ion-flash-off:before{content:"\f136"}.ion-folder:before{content:"\f139"}.ion-fork:before{content:"\f27a"}.ion-fork-repo:before{content:"\f2c0"}.ion-forward:before{content:"\f13a"}.ion-funnel:before{content:"\f31b"}.ion-gear-a:before{content:"\f13d"}.ion-gear-b:before{content:"\f13e"}.ion-grid:before{content:"\f13f"}.ion-hammer:before{content:"\f27b"}.ion-happy:before{content:"\f31c"}.ion-happy-outline:before{content:"\f3c6"}.ion-headphone:before{content:"\f140"}.ion-heart:before{content:"\f141"}.ion-heart-broken:before{content:"\f31d"}.ion-help:before{content:"\f143"}.ion-help-buoy:before{content:"\f27c"}.ion-help-circled:before{content:"\f142"}.ion-home:before{content:"\f144"}.ion-icecream:before{content:"\f27d"}.ion-image:before{content:"\f147"}.ion-images:before{content:"\f148"}.ion-information:before{content:"\f14a"}.ion-information-circled:before{content:"\f149"}.ion-ionic:before{content:"\f14b"}.ion-ios-alarm:before{content:"\f3c8"}.ion-ios-alarm-outline:before{content:"\f3c7"}.ion-ios-albums:before{content:"\f3ca"}.ion-ios-albums-outline:before{content:"\f3c9"}.ion-ios-americanfootball:before{content:"\f3cc"}.ion-ios-americanfootball-outline:before{content:"\f3cb"}.ion-ios-analytics:before{content:"\f3ce"}.ion-ios-analytics-outline:before{content:"\f3cd"}.ion-ios-arrow-back:before{content:"\f3cf"}.ion-ios-arrow-down:before{content:"\f3d0"}.ion-ios-arrow-forward:before{content:"\f3d1"}.ion-ios-arrow-left:before{content:"\f3d2"}.ion-ios-arrow-right:before{content:"\f3d3"}.ion-ios-arrow-thin-down:before{content:"\f3d4"}.ion-ios-arrow-thin-left:before{content:"\f3d5"}.ion-ios-arrow-thin-right:before{content:"\f3d6"}.ion-ios-arrow-thin-up:before{content:"\f3d7"}.ion-ios-arrow-up:before{content:"\f3d8"}.ion-ios-at:before{content:"\f3da"}.ion-ios-at-outline:before{content:"\f3d9"}.ion-ios-barcode:before{content:"\f3dc"}.ion-ios-barcode-outline:before{content:"\f3db"}.ion-ios-baseball:before{content:"\f3de"}.ion-ios-baseball-outline:before{content:"\f3dd"}.ion-ios-basketball:before{content:"\f3e0"}.ion-ios-basketball-outline:before{content:"\f3df"}.ion-ios-bell:before{content:"\f3e2"}.ion-ios-bell-outline:before{content:"\f3e1"}.ion-ios-body:before{content:"\f3e4"}.ion-ios-body-outline:before{content:"\f3e3"}.ion-ios-bolt:before{content:"\f3e6"}.ion-ios-bolt-outline:before{content:"\f3e5"}.ion-ios-book:before{content:"\f3e8"}.ion-ios-book-outline:before{content:"\f3e7"}.ion-ios-bookmarks:before{content:"\f3ea"}.ion-ios-bookmarks-outline:before{content:"\f3e9"}.ion-ios-box:before{content:"\f3ec"}.ion-ios-box-outline:before{content:"\f3eb"}.ion-ios-briefcase:before{content:"\f3ee"}.ion-ios-briefcase-outline:before{content:"\f3ed"}.ion-ios-browsers:before{content:"\f3f0"}.ion-ios-browsers-outline:before{content:"\f3ef"}.ion-ios-calculator:before{content:"\f3f2"}.ion-ios-calculator-outline:before{content:"\f3f1"}.ion-ios-calendar:before{content:"\f3f4"}.ion-ios-calendar-outline:before{content:"\f3f3"}.ion-ios-camera:before{content:"\f3f6"}.ion-ios-camera-outline:before{content:"\f3f5"}.ion-ios-cart:before{content:"\f3f8"}.ion-ios-cart-outline:before{content:"\f3f7"}.ion-ios-chatboxes:before{content:"\f3fa"}.ion-ios-chatboxes-outline:before{content:"\f3f9"}.ion-ios-chatbubble:before{content:"\f3fc"}.ion-ios-chatbubble-outline:before{content:"\f3fb"}.ion-ios-checkmark:before{content:"\f3ff"}.ion-ios-checkmark-empty:before{content:"\f3fd"}.ion-ios-checkmark-outline:before{content:"\f3fe"}.ion-ios-circle-filled:before{content:"\f400"}.ion-ios-circle-outline:before{content:"\f401"}.ion-ios-clock:before{content:"\f403"}.ion-ios-clock-outline:before{content:"\f402"}.ion-ios-close:before{content:"\f406"}.ion-ios-close-empty:before{content:"\f404"}.ion-ios-close-outline:before{content:"\f405"}.ion-ios-cloud:before{content:"\f40c"}.ion-ios-cloud-download:before{content:"\f408"}.ion-ios-cloud-download-outline:before{content:"\f407"}.ion-ios-cloud-outline:before{content:"\f409"}.ion-ios-cloud-upload:before{content:"\f40b"}.ion-ios-cloud-upload-outline:before{content:"\f40a"}.ion-ios-cloudy:before{content:"\f410"}.ion-ios-cloudy-night:before{content:"\f40e"}.ion-ios-cloudy-night-outline:before{content:"\f40d"}.ion-ios-cloudy-outline:before{content:"\f40f"}.ion-ios-cog:before{content:"\f412"}.ion-ios-cog-outline:before{content:"\f411"}.ion-ios-color-filter:before{content:"\f414"}.ion-ios-color-filter-outline:before{content:"\f413"}.ion-ios-color-wand:before{content:"\f416"}.ion-ios-color-wand-outline:before{content:"\f415"}.ion-ios-compose:before{content:"\f418"}.ion-ios-compose-outline:before{content:"\f417"}.ion-ios-contact:before{content:"\f41a"}.ion-ios-contact-outline:before{content:"\f419"}.ion-ios-copy:before{content:"\f41c"}.ion-ios-copy-outline:before{content:"\f41b"}.ion-ios-crop:before{content:"\f41e"}.ion-ios-crop-strong:before{content:"\f41d"}.ion-ios-download:before{content:"\f420"}.ion-ios-download-outline:before{content:"\f41f"}.ion-ios-drag:before{content:"\f421"}.ion-ios-email:before{content:"\f423"}.ion-ios-email-outline:before{content:"\f422"}.ion-ios-eye:before{content:"\f425"}.ion-ios-eye-outline:before{content:"\f424"}.ion-ios-fastforward:before{content:"\f427"}.ion-ios-fastforward-outline:before{content:"\f426"}.ion-ios-filing:before{content:"\f429"}.ion-ios-filing-outline:before{content:"\f428"}.ion-ios-film:before{content:"\f42b"}.ion-ios-film-outline:before{content:"\f42a"}.ion-ios-flag:before{content:"\f42d"}.ion-ios-flag-outline:before{content:"\f42c"}.ion-ios-flame:before{content:"\f42f"}.ion-ios-flame-outline:before{content:"\f42e"}.ion-ios-flask:before{content:"\f431"}.ion-ios-flask-outline:before{content:"\f430"}.ion-ios-flower:before{content:"\f433"}.ion-ios-flower-outline:before{content:"\f432"}.ion-ios-folder:before{content:"\f435"}.ion-ios-folder-outline:before{content:"\f434"}.ion-ios-football:before{content:"\f437"}.ion-ios-football-outline:before{content:"\f436"}.ion-ios-game-controller-a:before{content:"\f439"}.ion-ios-game-controller-a-outline:before{content:"\f438"}.ion-ios-game-controller-b:before{content:"\f43b"}.ion-ios-game-controller-b-outline:before{content:"\f43a"}.ion-ios-gear:before{content:"\f43d"}.ion-ios-gear-outline:before{content:"\f43c"}.ion-ios-glasses:before{content:"\f43f"}.ion-ios-glasses-outline:before{content:"\f43e"}.ion-ios-grid-view:before{content:"\f441"}.ion-ios-grid-view-outline:before{content:"\f440"}.ion-ios-heart:before{content:"\f443"}.ion-ios-heart-outline:before{content:"\f442"}.ion-ios-help:before{content:"\f446"}.ion-ios-help-empty:before{content:"\f444"}.ion-ios-help-outline:before{content:"\f445"}.ion-ios-home:before{content:"\f448"}.ion-ios-home-outline:before{content:"\f447"}.ion-ios-infinite:before{content:"\f44a"}.ion-ios-infinite-outline:before{content:"\f449"}.ion-ios-information:before{content:"\f44d"}.ion-ios-information-empty:before{content:"\f44b"}.ion-ios-information-outline:before{content:"\f44c"}.ion-ios-ionic-outline:before{content:"\f44e"}.ion-ios-keypad:before{content:"\f450"}.ion-ios-keypad-outline:before{content:"\f44f"}.ion-ios-lightbulb:before{content:"\f452"}.ion-ios-lightbulb-outline:before{content:"\f451"}.ion-ios-list:before{content:"\f454"}.ion-ios-list-outline:before{content:"\f453"}.ion-ios-location:before{content:"\f456"}.ion-ios-location-outline:before{content:"\f455"}.ion-ios-locked:before{content:"\f458"}.ion-ios-locked-outline:before{content:"\f457"}.ion-ios-loop:before{content:"\f45a"}.ion-ios-loop-strong:before{content:"\f459"}.ion-ios-medical:before{content:"\f45c"}.ion-ios-medical-outline:before{content:"\f45b"}.ion-ios-medkit:before{content:"\f45e"}.ion-ios-medkit-outline:before{content:"\f45d"}.ion-ios-mic:before{content:"\f461"}.ion-ios-mic-off:before{content:"\f45f"}.ion-ios-mic-outline:before{content:"\f460"}.ion-ios-minus:before{content:"\f464"}.ion-ios-minus-empty:before{content:"\f462"}.ion-ios-minus-outline:before{content:"\f463"}.ion-ios-monitor:before{content:"\f466"}.ion-ios-monitor-outline:before{content:"\f465"}.ion-ios-moon:before{content:"\f468"}.ion-ios-moon-outline:before{content:"\f467"}.ion-ios-more:before{content:"\f46a"}.ion-ios-more-outline:before{content:"\f469"}.ion-ios-musical-note:before{content:"\f46b"}.ion-ios-musical-notes:before{content:"\f46c"}.ion-ios-navigate:before{content:"\f46e"}.ion-ios-navigate-outline:before{content:"\f46d"}.ion-ios-nutrition:before{content:"\f470"}.ion-ios-nutrition-outline:before{content:"\f46f"}.ion-ios-paper:before{content:"\f472"}.ion-ios-paper-outline:before{content:"\f471"}.ion-ios-paperplane:before{content:"\f474"}.ion-ios-paperplane-outline:before{content:"\f473"}.ion-ios-partlysunny:before{content:"\f476"}.ion-ios-partlysunny-outline:before{content:"\f475"}.ion-ios-pause:before{content:"\f478"}.ion-ios-pause-outline:before{content:"\f477"}.ion-ios-paw:before{content:"\f47a"}.ion-ios-paw-outline:before{content:"\f479"}.ion-ios-people:before{content:"\f47c"}.ion-ios-people-outline:before{content:"\f47b"}.ion-ios-person:before{content:"\f47e"}.ion-ios-person-outline:before{content:"\f47d"}.ion-ios-personadd:before{content:"\f480"}.ion-ios-personadd-outline:before{content:"\f47f"}.ion-ios-photos:before{content:"\f482"}.ion-ios-photos-outline:before{content:"\f481"}.ion-ios-pie:before{content:"\f484"}.ion-ios-pie-outline:before{content:"\f483"}.ion-ios-pint:before{content:"\f486"}.ion-ios-pint-outline:before{content:"\f485"}.ion-ios-play:before{content:"\f488"}.ion-ios-play-outline:before{content:"\f487"}.ion-ios-plus:before{content:"\f48b"}.ion-ios-plus-empty:before{content:"\f489"}.ion-ios-plus-outline:before{content:"\f48a"}.ion-ios-pricetag:before{content:"\f48d"}.ion-ios-pricetag-outline:before{content:"\f48c"}.ion-ios-pricetags:before{content:"\f48f"}.ion-ios-pricetags-outline:before{content:"\f48e"}.ion-ios-printer:before{content:"\f491"}.ion-ios-printer-outline:before{content:"\f490"}.ion-ios-pulse:before{content:"\f493"}.ion-ios-pulse-strong:before{content:"\f492"}.ion-ios-rainy:before{content:"\f495"}.ion-ios-rainy-outline:before{content:"\f494"}.ion-ios-recording:before{content:"\f497"}.ion-ios-recording-outline:before{content:"\f496"}.ion-ios-redo:before{content:"\f499"}.ion-ios-redo-outline:before{content:"\f498"}.ion-ios-refresh:before{content:"\f49c"}.ion-ios-refresh-empty:before{content:"\f49a"}.ion-ios-refresh-outline:before{content:"\f49b"}.ion-ios-reload:before{content:"\f49d"}.ion-ios-reverse-camera:before{content:"\f49f"}.ion-ios-reverse-camera-outline:before{content:"\f49e"}.ion-ios-rewind:before{content:"\f4a1"}.ion-ios-rewind-outline:before{content:"\f4a0"}.ion-ios-rose:before{content:"\f4a3"}.ion-ios-rose-outline:before{content:"\f4a2"}.ion-ios-search:before{content:"\f4a5"}.ion-ios-search-strong:before{content:"\f4a4"}.ion-ios-settings:before{content:"\f4a7"}.ion-ios-settings-strong:before{content:"\f4a6"}.ion-ios-shuffle:before{content:"\f4a9"}.ion-ios-shuffle-strong:before{content:"\f4a8"}.ion-ios-skipbackward:before{content:"\f4ab"}.ion-ios-skipbackward-outline:before{content:"\f4aa"}.ion-ios-skipforward:before{content:"\f4ad"}.ion-ios-skipforward-outline:before{content:"\f4ac"}.ion-ios-snowy:before{content:"\f4ae"}.ion-ios-speedometer:before{content:"\f4b0"}.ion-ios-speedometer-outline:before{content:"\f4af"}.ion-ios-star:before{content:"\f4b3"}.ion-ios-star-half:before{content:"\f4b1"}.ion-ios-star-outline:before{content:"\f4b2"}.ion-ios-stopwatch:before{content:"\f4b5"}.ion-ios-stopwatch-outline:before{content:"\f4b4"}.ion-ios-sunny:before{content:"\f4b7"}.ion-ios-sunny-outline:before{content:"\f4b6"}.ion-ios-telephone:before{content:"\f4b9"}.ion-ios-telephone-outline:before{content:"\f4b8"}.ion-ios-tennisball:before{content:"\f4bb"}.ion-ios-tennisball-outline:before{content:"\f4ba"}.ion-ios-thunderstorm:before{content:"\f4bd"}.ion-ios-thunderstorm-outline:before{content:"\f4bc"}.ion-ios-time:before{content:"\f4bf"}.ion-ios-time-outline:before{content:"\f4be"}.ion-ios-timer:before{content:"\f4c1"}.ion-ios-timer-outline:before{content:"\f4c0"}.ion-ios-toggle:before{content:"\f4c3"}.ion-ios-toggle-outline:before{content:"\f4c2"}.ion-ios-trash:before{content:"\f4c5"}.ion-ios-trash-outline:before{content:"\f4c4"}.ion-ios-undo:before{content:"\f4c7"}.ion-ios-undo-outline:before{content:"\f4c6"}.ion-ios-unlocked:before{content:"\f4c9"}.ion-ios-unlocked-outline:before{content:"\f4c8"}.ion-ios-upload:before{content:"\f4cb"}.ion-ios-upload-outline:before{content:"\f4ca"}.ion-ios-videocam:before{content:"\f4cd"}.ion-ios-videocam-outline:before{content:"\f4cc"}.ion-ios-volume-high:before{content:"\f4ce"}.ion-ios-volume-low:before{content:"\f4cf"}.ion-ios-wineglass:before{content:"\f4d1"}.ion-ios-wineglass-outline:before{content:"\f4d0"}.ion-ios-world:before{content:"\f4d3"}.ion-ios-world-outline:before{content:"\f4d2"}.ion-ipad:before{content:"\f1f9"}.ion-iphone:before{content:"\f1fa"}.ion-ipod:before{content:"\f1fb"}.ion-jet:before{content:"\f295"}.ion-key:before{content:"\f296"}.ion-knife:before{content:"\f297"}.ion-laptop:before{content:"\f1fc"}.ion-leaf:before{content:"\f1fd"}.ion-levels:before{content:"\f298"}.ion-lightbulb:before{content:"\f299"}.ion-link:before{content:"\f1fe"}.ion-load-a:before{content:"\f29a"}.ion-load-b:before{content:"\f29b"}.ion-load-c:before{content:"\f29c"}.ion-load-d:before{content:"\f29d"}.ion-location:before{content:"\f1ff"}.ion-lock-combination:before{content:"\f4d4"}.ion-locked:before{content:"\f200"}.ion-log-in:before{content:"\f29e"}.ion-log-out:before{content:"\f29f"}.ion-loop:before{content:"\f201"}.ion-magnet:before{content:"\f2a0"}.ion-male:before{content:"\f2a1"}.ion-man:before{content:"\f202"}.ion-map:before{content:"\f203"}.ion-medkit:before{content:"\f2a2"}.ion-merge:before{content:"\f33f"}.ion-mic-a:before{content:"\f204"}.ion-mic-b:before{content:"\f205"}.ion-mic-c:before{content:"\f206"}.ion-minus:before{content:"\f209"}.ion-minus-circled:before{content:"\f207"}.ion-minus-round:before{content:"\f208"}.ion-model-s:before{content:"\f2c1"}.ion-monitor:before{content:"\f20a"}.ion-more:before{content:"\f20b"}.ion-mouse:before{content:"\f340"}.ion-music-note:before{content:"\f20c"}.ion-navicon:before{content:"\f20e"}.ion-navicon-round:before{content:"\f20d"}.ion-navigate:before{content:"\f2a3"}.ion-network:before{content:"\f341"}.ion-no-smoking:before{content:"\f2c2"}.ion-nuclear:before{content:"\f2a4"}.ion-outlet:before{content:"\f342"}.ion-paintbrush:before{content:"\f4d5"}.ion-paintbucket:before{content:"\f4d6"}.ion-paper-airplane:before{content:"\f2c3"}.ion-paperclip:before{content:"\f20f"}.ion-pause:before{content:"\f210"}.ion-person:before{content:"\f213"}.ion-person-add:before{content:"\f211"}.ion-person-stalker:before{content:"\f212"}.ion-pie-graph:before{content:"\f2a5"}.ion-pin:before{content:"\f2a6"}.ion-pinpoint:before{content:"\f2a7"}.ion-pizza:before{content:"\f2a8"}.ion-plane:before{content:"\f214"}.ion-planet:before{content:"\f343"}.ion-play:before{content:"\f215"}.ion-playstation:before{content:"\f30a"}.ion-plus:before{content:"\f218"}.ion-plus-circled:before{content:"\f216"}.ion-plus-round:before{content:"\f217"}.ion-podium:before{content:"\f344"}.ion-pound:before{content:"\f219"}.ion-power:before{content:"\f2a9"}.ion-pricetag:before{content:"\f2aa"}.ion-pricetags:before{content:"\f2ab"}.ion-printer:before{content:"\f21a"}.ion-pull-request:before{content:"\f345"}.ion-qr-scanner:before{content:"\f346"}.ion-quote:before{content:"\f347"}.ion-radio-waves:before{content:"\f2ac"}.ion-record:before{content:"\f21b"}.ion-refresh:before{content:"\f21c"}.ion-reply:before{content:"\f21e"}.ion-reply-all:before{content:"\f21d"}.ion-ribbon-a:before{content:"\f348"}.ion-ribbon-b:before{content:"\f349"}.ion-sad:before{content:"\f34a"}.ion-sad-outline:before{content:"\f4d7"}.ion-scissors:before{content:"\f34b"}.ion-search:before{content:"\f21f"}.ion-settings:before{content:"\f2ad"}.ion-share:before{content:"\f220"}.ion-shuffle:before{content:"\f221"}.ion-skip-backward:before{content:"\f222"}.ion-skip-forward:before{content:"\f223"}.ion-social-android:before{content:"\f225"}.ion-social-android-outline:before{content:"\f224"}.ion-social-angular:before{content:"\f4d9"}.ion-social-angular-outline:before{content:"\f4d8"}.ion-social-apple:before{content:"\f227"}.ion-social-apple-outline:before{content:"\f226"}.ion-social-bitcoin:before{content:"\f2af"}.ion-social-bitcoin-outline:before{content:"\f2ae"}.ion-social-buffer:before{content:"\f229"}.ion-social-buffer-outline:before{content:"\f228"}.ion-social-chrome:before{content:"\f4db"}.ion-social-chrome-outline:before{content:"\f4da"}.ion-social-codepen:before{content:"\f4dd"}.ion-social-codepen-outline:before{content:"\f4dc"}.ion-social-css3:before{content:"\f4df"}.ion-social-css3-outline:before{content:"\f4de"}.ion-social-designernews:before{content:"\f22b"}.ion-social-designernews-outline:before{content:"\f22a"}.ion-social-dribbble:before{content:"\f22d"}.ion-social-dribbble-outline:before{content:"\f22c"}.ion-social-dropbox:before{content:"\f22f"}.ion-social-dropbox-outline:before{content:"\f22e"}.ion-social-euro:before{content:"\f4e1"}.ion-social-euro-outline:before{content:"\f4e0"}.ion-social-facebook:before{content:"\f231"}.ion-social-facebook-outline:before{content:"\f230"}.ion-social-foursquare:before{content:"\f34d"}.ion-social-foursquare-outline:before{content:"\f34c"}.ion-social-freebsd-devil:before{content:"\f2c4"}.ion-social-github:before{content:"\f233"}.ion-social-github-outline:before{content:"\f232"}.ion-social-google:before{content:"\f34f"}.ion-social-google-outline:before{content:"\f34e"}.ion-social-googleplus:before{content:"\f235"}.ion-social-googleplus-outline:before{content:"\f234"}.ion-social-hackernews:before{content:"\f237"}.ion-social-hackernews-outline:before{content:"\f236"}.ion-social-html5:before{content:"\f4e3"}.ion-social-html5-outline:before{content:"\f4e2"}.ion-social-instagram:before{content:"\f351"}.ion-social-instagram-outline:before{content:"\f350"}.ion-social-javascript:before{content:"\f4e5"}.ion-social-javascript-outline:before{content:"\f4e4"}.ion-social-linkedin:before{content:"\f239"}.ion-social-linkedin-outline:before{content:"\f238"}.ion-social-markdown:before{content:"\f4e6"}.ion-social-nodejs:before{content:"\f4e7"}.ion-social-octocat:before{content:"\f4e8"}.ion-social-pinterest:before{content:"\f2b1"}.ion-social-pinterest-outline:before{content:"\f2b0"}.ion-social-python:before{content:"\f4e9"}.ion-social-reddit:before{content:"\f23b"}.ion-social-reddit-outline:before{content:"\f23a"}.ion-social-rss:before{content:"\f23d"}.ion-social-rss-outline:before{content:"\f23c"}.ion-social-sass:before{content:"\f4ea"}.ion-social-skype:before{content:"\f23f"}.ion-social-skype-outline:before{content:"\f23e"}.ion-social-snapchat:before{content:"\f4ec"}.ion-social-snapchat-outline:before{content:"\f4eb"}.ion-social-tumblr:before{content:"\f241"}.ion-social-tumblr-outline:before{content:"\f240"}.ion-social-tux:before{content:"\f2c5"}.ion-social-twitch:before{content:"\f4ee"}.ion-social-twitch-outline:before{content:"\f4ed"}.ion-social-twitter:before{content:"\f243"}.ion-social-twitter-outline:before{content:"\f242"}.ion-social-usd:before{content:"\f353"}.ion-social-usd-outline:before{content:"\f352"}.ion-social-vimeo:before{content:"\f245"}.ion-social-vimeo-outline:before{content:"\f244"}.ion-social-whatsapp:before{content:"\f4f0"}.ion-social-whatsapp-outline:before{content:"\f4ef"}.ion-social-windows:before{content:"\f247"}.ion-social-windows-outline:before{content:"\f246"}.ion-social-wordpress:before{content:"\f249"}.ion-social-wordpress-outline:before{content:"\f248"}.ion-social-yahoo:before{content:"\f24b"}.ion-social-yahoo-outline:before{content:"\f24a"}.ion-social-yen:before{content:"\f4f2"}.ion-social-yen-outline:before{content:"\f4f1"}.ion-social-youtube:before{content:"\f24d"}.ion-social-youtube-outline:before{content:"\f24c"}.ion-soup-can:before{content:"\f4f4"}.ion-soup-can-outline:before{content:"\f4f3"}.ion-speakerphone:before{content:"\f2b2"}.ion-speedometer:before{content:"\f2b3"}.ion-spoon:before{content:"\f2b4"}.ion-star:before{content:"\f24e"}.ion-stats-bars:before{content:"\f2b5"}.ion-steam:before{content:"\f30b"}.ion-stop:before{content:"\f24f"}.ion-thermometer:before{content:"\f2b6"}.ion-thumbsdown:before{content:"\f250"}.ion-thumbsup:before{content:"\f251"}.ion-toggle:before{content:"\f355"}.ion-toggle-filled:before{content:"\f354"}.ion-transgender:before{content:"\f4f5"}.ion-trash-a:before{content:"\f252"}.ion-trash-b:before{content:"\f253"}.ion-trophy:before{content:"\f356"}.ion-tshirt:before{content:"\f4f7"}.ion-tshirt-outline:before{content:"\f4f6"}.ion-umbrella:before{content:"\f2b7"}.ion-university:before{content:"\f357"}.ion-unlocked:before{content:"\f254"}.ion-upload:before{content:"\f255"}.ion-usb:before{content:"\f2b8"}.ion-videocamera:before{content:"\f256"}.ion-volume-high:before{content:"\f257"}.ion-volume-low:before{content:"\f258"}.ion-volume-medium:before{content:"\f259"}.ion-volume-mute:before{content:"\f25a"}.ion-wand:before{content:"\f358"}.ion-waterdrop:before{content:"\f25b"}.ion-wifi:before{content:"\f25c"}.ion-wineglass:before{content:"\f2b9"}.ion-woman:before{content:"\f25d"}.ion-wrench:before{content:"\f2ba"}.ion-xbox:before{content:"\f30c"} diff --git a/docs/modern-async/1.0.4/styles/third-party/prettify-jsdoc.css b/docs/modern-async/1.0.4/styles/third-party/prettify-jsdoc.css new file mode 100644 index 0000000..834a866 --- /dev/null +++ b/docs/modern-async/1.0.4/styles/third-party/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: hsl(104, 100%, 24%); + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/docs/modern-async/1.0.4/styles/third-party/prettify-tomorrow.css b/docs/modern-async/1.0.4/styles/third-party/prettify-tomorrow.css new file mode 100644 index 0000000..0d3b79c --- /dev/null +++ b/docs/modern-async/1.0.4/styles/third-party/prettify-tomorrow.css @@ -0,0 +1,5 @@ +ol.linenums { + margin-top: 0; + margin-bottom: 0; + list-style-position: outside; +} diff --git a/docs/modern-async/1.0.4/timeout.mjs.html b/docs/modern-async/1.0.4/timeout.mjs.html new file mode 100644 index 0000000..10b0f3c --- /dev/null +++ b/docs/modern-async/1.0.4/timeout.mjs.html @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + timeout.mjs + + + + + + + + + + + + + + + + + + + +
    + +

    timeout.mjs

    + + + + + + + +
    +
    +
    
    +import sleepCancellable from './sleepCancellable.mjs'
    +import TimeoutError from './TimeoutError.mjs'
    +import asyncWrap from './asyncWrap.mjs'
    +import Deferred from './Deferred.mjs'
    +
    +/**
    + * Wraps a call to an asynchronous function to add a timer on it. If the delay is exceeded
    + * the returned promise will be rejected with a `TimeoutError`.
    + *
    + * This function uses `setTimeout()` internally and has the same behavior, notably that it could reject
    + * after the asked time (depending on other tasks running in the event loop) or a few milliseconds before.
    + *
    + * @param {Function} fct An asynchronous function that will be called immediately without arguments.
    + * @param {number} amount An amount of time in milliseconds
    + * @returns {Promise} A promise that will be resolved or rejected according to the result of the call
    + * to `fct`. If `amount` milliseconds pass before the call to `fct` returns or rejects, this promise will
    + * be rejected with a `TimeoutError`.
    + * @example
    + * import { timeout, sleep, asyncRoot } from 'modern-async'
    + *
    + * asyncRoot(async () => {
    + *   // the following statement will perform successfully because
    + *   // the function will return before the delay
    + *   await timeout(async () => {
    + *     await sleep(10)
    + *   }, 100)
    + *
    + *   try {
    + *     // the following statement will throw after 10ms
    + *     await timeout(async () => {
    + *       await sleep(100)
    + *     }, 10)
    + *   } catch (e) {
    + *     console.log(e.name) // prints TimeoutError
    + *   }
    + * })
    + */
    +async function timeout (fct, amount) {
    +  const asyncFct = asyncWrap(fct)
    +
    +  const [timoutPromise, cancelTimeout] = sleepCancellable(amount)
    +
    +  const basePromise = asyncFct()
    +
    +  const deferred = new Deferred()
    +
    +  basePromise.then(deferred.resolve, deferred.reject)
    +
    +  timoutPromise.then(() => {
    +    deferred.reject(new TimeoutError())
    +  }, () => {
    +    // ignore CancelledError
    +  })
    +
    +  return deferred.promise.finally(cancelTimeout)
    +}
    +
    +export default timeout
    +
    +
    +
    + + + + +
    + +
    + modern-async is licensed under the terms of the MIT license +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/modern-async/1.0.4/timeoutPrecise.mjs.html b/docs/modern-async/1.0.4/timeoutPrecise.mjs.html new file mode 100644 index 0000000..a728d24 --- /dev/null +++ b/docs/modern-async/1.0.4/timeoutPrecise.mjs.html @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + timeoutPrecise.mjs + + + + + + + + + + + + + + + + + + + +
    + +

    timeoutPrecise.mjs

    + + + + + + + +
    +
    +
    
    +import sleepPreciseCancellable from './sleepPreciseCancellable.mjs'
    +import TimeoutError from './TimeoutError.mjs'
    +import asyncWrap from './asyncWrap.mjs'
    +import Deferred from './Deferred.mjs'
    +
    +/**
    + * Wraps a call to an asynchronous function to add a timer on it. If the delay is exceeded
    + * the returned promise will be rejected with a `TimeoutError`.
    + *
    + * This function is similar to `timeout()` 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 {Function} fct An asynchronous function that will be called immediately without arguments.
    + * @param {number} amount An amount of time in milliseconds
    + * @returns {Promise} A promise that will be resolved or rejected according to the result of the call
    + * to `fct`. If `amount` milliseconds pass before the call to `fct` returns or rejects, this promise will
    + * be rejected with a `TimeoutError`.
    + * @example
    + * import { timeoutPrecise, sleep, asyncRoot } from 'modern-async'
    + *
    + * asyncRoot(async () => {
    + *   // the following statement will perform successfully because
    + *   // the function will return before the delay
    + *   await timeoutPrecise(async () => {
    + *     await sleep(10)
    + *   }, 100)
    + *
    + *   try {
    + *     // the following statement will throw after 10ms
    + *     await timeoutPrecise(async () => {
    + *       await sleep(100)
    + *     }, 10)
    + *   } catch (e) {
    + *     console.log(e.name) // prints TimeoutError
    + *   }
    + * })
    + */
    +async function timeoutPrecise (fct, amount) {
    +  const asyncFct = asyncWrap(fct)
    +
    +  const [timoutPromise, cancelTimeout] = sleepPreciseCancellable(amount)
    +
    +  const basePromise = asyncFct()
    +
    +  const deferred = new Deferred()
    +
    +  basePromise.then(deferred.resolve, deferred.reject)
    +
    +  timoutPromise.then(() => {
    +    deferred.reject(new TimeoutError())
    +  }, () => {
    +    // ignore CancelledError
    +  })
    +
    +  return deferred.promise.finally(cancelTimeout)
    +}
    +
    +export default timeoutPrecise
    +
    +
    +
    + + + + +
    + +
    + modern-async is licensed under the terms of the MIT license +
    + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/versions.json b/docs/versions.json index 10019be..49c3eb2 100644 --- a/docs/versions.json +++ b/docs/versions.json @@ -1 +1 @@ -{"versions":["1.0.3","1.0.2","1.0.1","1.0.0"]} \ No newline at end of file +{"versions":["1.0.4","1.0.3","1.0.2","1.0.1","1.0.0"]} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 596775a..b192c1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,12 @@ { "name": "modern-async", - "version": "1.0.3", + "version": "1.0.4", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "1.0.3", + "name": "modern-async", + "version": "1.0.4", "license": "MIT", "dependencies": { "nanoassert": "^2.0.0" diff --git a/package.json b/package.json index b5ac571..a83ad32 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "modern-async", - "version": "1.0.3", + "version": "1.0.4", "description": "A modern tooling library for asynchronous operations using async/await and promises", "keywords": [ "async",