npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@chaisser/wait-for

v1.0.0

Published

Promise-based wait: sleep, waitUntil, waitWithTimeout

Readme

⏳ @chaisser/wait-for

Promise-based wait utilities: sleep, waitUntil, retry, debounce, throttle & more


✨ Features

  • 🎯 Type-safe - Full TypeScript support with generics
  • 😴 Sleep / Delay - Simple promise-based timers
  • 🔄 Wait Until - Poll until a condition is true with timeout
  • 🔁 Retry - Retry async functions with exponential backoff
  • ⏱️ Timeout - Wrap promises with timeout protection
  • 🎛️ Debounce & Throttle - Rate-limit function execution
  • 📡 Poller - Interval-based polling with start/stop control
  • ⏲️ Timer - Pause/resume countdown timer
  • 📊 Progress - Track elapsed time on long-running promises
  • 🪶 Zero dependencies - Lightweight and tree-shakeable
  • 🏎️ ESM + CJS - Dual module format support

📦 Installation

npm install @chaisser/wait-for
# or
yarn add @chaisser/wait-for
# or
pnpm add @chaisser/wait-for

🚀 Quick Start

import {
  sleep,
  waitFor,
  waitUntil,
  waitWithTimeout,
  retry,
  debounce,
  throttle,
  Poller,
  Timer,
} from '@chaisser/wait-for';

// Sleep for 1 second
await sleep(1000);

// Wait until a condition is true
await waitUntil(() => document.readyState === 'complete', { timeout: 10000 });

// Retry a flaky operation
const data = await retry(fetchData, { maxAttempts: 3, delay: 100, backoff: 2 });

// Wrap with timeout
const result = await waitWithTimeout(slowOperation(), 5000, 'Too slow!');

// Debounce rapid calls
const debouncedSave = debounce(saveToServer, 300);

📖 What It Does

This package provides a collection of async timing utilities for JavaScript and TypeScript. It handles everything from simple delays to complex retry logic with exponential backoff, polling, debouncing, throttling, and timeout-protected promises.


🎯 How It Works

The package is organized into categories:

  • Timers - sleep, waitFor, defer, nextTick
  • Conditionals - waitUntil, waitWithTimeout
  • Retry - retry with configurable attempts, delay, and backoff
  • Rate Limiting - debounce and throttle
  • Polling - Poller class for interval-based callbacks
  • Countdown - Timer class with pause/resume
  • Composition - waitForAll, waitForAny, waitForAllWithTimeout, waitForAnyWithTimeout
  • Progress - waitWithProgress for tracking elapsed time

🎨 What It's Useful For

  • API Calls - Retry failed requests with backoff
  • UI Wait States - Wait until DOM elements appear or state changes
  • Rate Limiting - Debounce search inputs, throttle scroll handlers
  • Testing - Sleep in tests, wait for async conditions
  • Polling - Periodically check for data updates
  • Timeouts - Prevent hanging on slow operations
  • Timers - Countdown timers with pause/resume support

💡 Usage Examples

Sleep & Delay

import { sleep, waitFor, defer, nextTick } from '@chaisser/wait-for';

// Sleep for 500ms
await sleep(500);

// Alias for sleep
await waitFor(500);

// Defer to next event loop
defer(() => console.log('later'));

// Next tick
nextTick(() => console.log('next'));

Wait Until Condition

import { waitUntil } from '@chaisser/wait-for';

// Wait with default settings (50ms interval, 5s timeout)
await waitUntil(() => isReady());

// Custom interval and timeout
await waitUntil(() => db.isConnected(), {
  interval: 100,
  timeout: 10000,
  timeoutMessage: 'Database connection failed'
});

Timeout Protection

import { waitWithTimeout } from '@chaisser/wait-for';

// Reject if operation takes longer than 5 seconds
const data = await waitWithTimeout(
  fetch('/api/data'),
  5000,
  'API request timed out'
);

Retry with Backoff

import { retry } from '@chaisser/wait-for';

// Retry up to 5 times with exponential backoff
const result = await retry(
  () => flakyApiCall(),
  {
    maxAttempts: 5,
    delay: 100,     // start at 100ms
    backoff: 2       // double each retry: 100, 200, 400, 800
  }
);

Debounce

import { debounce } from '@chaisser/wait-for';

const debouncedSearch = debounce((query: string) => {
  fetchResults(query);
}, 300);

// Only the last call executes after 300ms of silence
debouncedSearch('he');
debouncedSearch('hel');
debouncedSearch('hello'); // only this one fires

Throttle

import { throttle } from '@chaisser/wait-for';

const throttledScroll = throttle(() => {
  updateScrollPosition();
}, 100);

// Executes at most once per 100ms
window.addEventListener('scroll', throttledScroll);

Poller

import { Poller } from '@chaisser/wait-for';

const poller = new Poller(5000);

poller.on(() => {
  console.log('Polling for updates...');
  checkForUpdates();
});

// Stop after 1 minute
poller.stopAfter(60000);

// Manual control
poller.stop();
poller.start();
poller.isActive(); // true/false
poller.clear();    // remove all callbacks

Timer

import { Timer } from '@chaisser/wait-for';

const timer = new Timer(60, (remaining) => {
  console.log(`${remaining}s left`);
});

timer.start();
timer.pause();
timer.resume();
timer.stop();     // resets to initial value
timer.getRemaining(); // seconds left
timer.isActive();     // boolean

Promise Composition

import {
  waitForAll,
  waitForAny,
  waitForAllWithTimeout,
  waitForAnyWithTimeout,
} from '@chaisser/wait-for';

// Wait for all
const results = await waitForAll([
  fetchUsers(),
  fetchPosts(),
  fetchComments(),
]);

// Wait for first
const fastest = await waitForAny([
  fetchFromCDN1(),
  fetchFromCDN2(),
]);

// With timeout
const data = await waitForAllWithTimeout(
  [fetchA(), fetchB()],
  5000
);

Progress Tracking

import { waitWithProgress } from '@chaisser/wait-for';

const result = await waitWithProgress(
  longRunningOperation(),
  (elapsed) => {
    console.log(`Elapsed: ${elapsed}ms`);
  },
  500 // report every 500ms
);

📚 API Reference

Timers

| Function | Description | |---|---| | sleep(ms) | Resolve after specified milliseconds | | waitFor(ms) | Alias for sleep | | defer(fn) | Execute function in next event loop | | nextTick(fn) | Execute function in next tick |

Conditionals

| Function | Description | |---|---| | waitUntil(condition, options?) | Poll until condition returns true | | waitWithTimeout(promise, ms, msg?) | Reject if promise doesn't settle in time |

Retry

| Function | Description | |---|---| | retry(fn, options?) | Retry async fn with backoff (maxAttempts, delay, backoff) |

Rate Limiting

| Function | Description | |---|---| | debounce(fn, wait) | Delay fn until waitms of silence | | throttle(fn, wait) | Execute fn at most once per waitms |

Composition

| Function | Description | |---|---| | waitForAll(promises) | Promise.all wrapper | | waitForAny(promises) | Promise.race wrapper | | waitForAllWithTimeout(promises, ms) | All with timeout | | waitForAnyWithTimeout(promises, ms) | First with timeout | | waitWithProgress(promise, onProgress, interval?) | Track elapsed time |

Classes

| Class | Description | |---|---| | Poller | Interval-based polling with on(), start(), stop(), clear() | | Timer | Countdown timer with start(), pause(), resume(), stop() |


🔗 Related Packages

Explore our other utility packages in the @chaisser namespace:


🔒 License

MIT - Free to use in personal and commercial projects


👨 Developed by

Doruk Karaboncuk [email protected]


📄 Repository


🤝 Contributing

Contributions are welcome! Feel free to:

  • Report bugs
  • Suggest new features
  • Submit pull requests
  • Improve documentation

📞 Support

For issues, questions, or suggestions, please reach out through:


Made with ❤️ by @chaisser

npm license downloads typescript