Skip to content

Async Helpers

Small promise-based helpers for pausing and polling in async code. All three return promises, so use them with await.

import { sleep, usleep, until } from '@0x26e/utils'

Mind the units

sleep takes seconds; usleep takes milliseconds. So sleep(2) and usleep(2000) wait the same amount of time. The pause argument of until is also measured in seconds.

sleep

Pauses execution for a specified number of seconds. It resolves after the delay and returns nothing useful — await it to wait.

function sleep(s: number): Promise<void>

Parameters

ParameterTypeDescription
snumberThe number of seconds to wait.

Returns Promise<void> — resolves after the given number of seconds.

Example

console.log('start')
await sleep(2) // pauses for 2 seconds
console.log('two seconds later')

Internally sleep(s) simply calls usleep(s * 1000).

usleep

Pauses execution for a specified number of milliseconds. Use it when you need finer-grained delays than whole seconds.

function usleep(ms: number): Promise<void>

Parameters

ParameterTypeDescription
msnumberThe number of milliseconds to wait.

Returns Promise<void> — resolves after the given number of milliseconds.

Example

await usleep(500) // pauses for 500 milliseconds

A common use is spacing out a loop:

for (const item of items) {
  await process(item)
  await usleep(250) // throttle to ~4 per second
}

until

Continuously runs an attempt function until a condition returns true, pausing a fixed number of seconds between tries. It resolves with the last value returned by attempt.

function until<T>(
  condition: () => boolean | Promise<boolean>,
  attempt: () => T | Promise<T>,
  pause?: number,
): Promise<T>

Parameters

ParameterTypeDescription
condition() => boolean | Promise<boolean>Checked after each attempt. The loop stops when it returns true.
attempt() => T | Promise<T>Run on each iteration; its return value is what until resolves to.
pausenumber (optional)Seconds to wait between attempts. Defaults to 1.

Returns Promise<T> — the value returned by attempt once condition is satisfied.

How the loop runs

until always runs attempt at least once, then checks condition. While the condition is false, it sleeps for pause seconds and runs attempt again. Because the condition is checked after each attempt, the result of the final successful attempt is the one returned.

Examples

A minimal counter — keep attempting until the counter reaches 2, polling every 0.1 seconds:

let counter = 0
const result = await until(
  () => counter >= 2,
  async () => {
    counter += 1
    return counter
  },
  0.1,
)
console.log(result) // 2

A realistic polling case — wait for a background job to finish, checking every 2 seconds:

import { until } from '@0x26e/utils'
 
let job = await fetchJob(jobId)
 
const finished = await until(
  () => job.status === 'completed' || job.status === 'failed',
  async () => {
    job = await fetchJob(jobId)
    return job
  },
  2, // pause 2 seconds between checks
)
 
if (finished.status === 'completed') {
  console.log('Job done:', finished.result)
} else {
  console.error('Job failed:', finished.error)
}

Add your own timeout

until polls indefinitely until the condition is met — it has no built-in maximum number of attempts. If a stuck condition could loop forever, track an attempt count or a deadline inside your condition and resolve (or throw) when it's exceeded.

js-utils — A TypeScript utility collection similar to Laravel helpers. Released under the MIT license.