Utils (@pim.sk/utils)

wait

Async waiting utilities. sleep(ms) pauses execution for a fixed duration. to() polls a condition, selector or variable until it becomes truthy — with configurable timeout, interval and progress callback.
import { sleep, to } from '@pim.sk/utils/wait.mjs'

Examples

sleep( ms )

Pauses async execution for the given number of milliseconds. A thin wrapper around setTimeout — use with await inside an async function.

await sleep( 500 )    // pause 500 ms

// typical usage:
async function load() {
    showSpinner()
    await sleep( 1000 )
    hideSpinner()
}

// or chained:
sleep( 300 ).then( () => console.log("done") )
const t0 = performance.now()
await sleep( 1000 )
console.log( Math.round(performance.now() - t0) + " ms elapsed" )

to( fn ) — wait for condition

Polls a function until it returns truthy, then resolves. Useful for waiting until async state, a flag or computed value becomes ready. Default: max 100 intervals × 10 ms = 1 s total.

let data = undefined
setTimeout( () => { data = { user: "John" } }, 600 )

const result = await to( () => data !== undefined )

result.status          // → true   (condition met)
result.getStatus()
// → { status: true, time: 610, a: [ { name: fn, status: true, intervals: 62 } ] }
let data = undefined
setTimeout( () => { data = { user: "John" } }, 600 )

const result = await to( () => data !== undefined )

if( result.status ){
    console.log( "data is ready:", data )
    console.log( "waited intervals:", result.getStatus().a[0].intervals )
}

to( "#selector" ) — wait for DOM element

When passed a string, to() first tests it as a CSS selector. Resolves as soon as document.querySelector(str) returns an Element. Useful for waiting on dynamically injected content.

// element does not yet exist — will be added after 500 ms:
setTimeout( () => {
    const el = document.createElement("div")
    el.id = "my-widget"
    document.body.appendChild(el)
}, 500 )

const result = await to( "#my-widget" )

result.status   // → true
document.querySelector("#my-widget")  // → <div id="my-widget">

(target element will appear here)
const container = box.querySelector(".wait-sel-container")

setTimeout( () => {
    const el = document.createElement("span")
    el.id = "my-widget"
    el.textContent = "I appeared!"
    container.appendChild( el )
}, 500 )

const result = await to( "#my-widget" )

result.status   // → true

to( fn, { max, wait, progress, bErr } )

Full options object controls the polling behaviour. max × wait = total timeout window. progress(perc) is called each interval with 0–100. bErr: false suppresses the console warning on timeout.

const result = await to(
    () => someCondition(),
    {
        max:      50,           // max intervals (default 100)
        wait:     100,          // ms per interval (default 10)
        bErr:     false,        // suppress console error on timeout
        progress: (perc) => {
            progressBar.style.width = perc + "%"
        },
    }
)
// total window: 50 × 100 ms = 5 000 ms
// succeed after ~600 ms (counter reaches 6 at 100 ms × 6 intervals):
let counter = 0
const result = await to(
    () => ++counter >= 6,
    { max: 20, wait: 100, bErr: false,
      progress: p => progressBar.value = p }
)

// timeout — condition never met (bErr:false suppresses console warn):
const result = await to(
    () => false,
    { max: 10, wait: 100, bErr: false,
      progress: p => progressBar.value = p }
)

to( fn, callback ) — without await

Pass a callback function as the second argument (or use .then()) to handle the result without await. Useful when calling to() outside an async context or for fire-and-forget patterns.

// callback shorthand — function argument = js option:
to(
    () => typeof myVar !== "undefined",
    () => { console.log("ready!") }
)

// same as:
to( () => typeof myVar !== "undefined", { js: () => { console.log("ready!") } } )

// or .then():
to( () => typeof myVar !== "undefined" )
    .then( result => { console.log("status:", result.status) } )
let flag = false
setTimeout( () => { flag = true }, 400 )

// 1. callback shorthand (function argument):
to(
    () => flag === true,
    () => { output.textContent += "callback fired — flag is true\n" }
)

// 2. same via { js } option:
to(
    () => flag === true,
    { js: () => { output.textContent += "js option fired\n" } }
)

// 3. .then() variant:
to( () => flag === true )
    .then( result => {
        output.textContent += `then — status: ${result.status}\n`
    } )

// code continues immediately (non-blocking):
output.textContent += `flag at this moment: ${flag}\n`
v 1.1.2