async-wait-until

October 16, 2025 ยท View on GitHub

A lightweight, zero-dependency library for waiting asynchronously until a specific condition is met. Works in any JavaScript environment that supports Promises, including older Node.js versions and browsers (with polyfills if necessary).

npm version npm downloads MIT License Maintainability

โœจ Features

  • ๐Ÿš€ Zero dependencies - Lightweight and fast
  • ๐Ÿ”ง TypeScript support - Full TypeScript definitions included
  • ๐ŸŒ Universal compatibility - Works in Node.js and browsers
  • โšก Flexible configuration - Customizable timeouts and intervals
  • ๐ŸŽฏ Promise-based - Clean async/await syntax
  • ๐Ÿ“ฆ Multiple formats - UMD, ESM, and additional format bundles
  • ๐Ÿ›ก๏ธ Error handling - Built-in timeout error handling

๐Ÿ“š Table of Contents

๐Ÿ“– Detailed Documentation

For detailed documentation, visit https://devlato.github.io/async-wait-until/


๐Ÿš€ Installation

Install using npm:

npm install async-wait-until

The library includes UMD and ESM bundles (plus additional formats), so you can use it in any environment.

import { waitUntil } from 'async-wait-until';

// Example: Wait for an element to appear
await waitUntil(() => document.querySelector('#target') !== null);

๐Ÿ› ๏ธ How to Use

Basic Example: Wait for a DOM Element

import { waitUntil } from 'async-wait-until';

const waitForElement = async () => {
  // Wait for an element with the ID "target" to appear
  const element = await waitUntil(() => document.querySelector('#target'), { timeout: 5000 });
  console.log('Element found:', element);
};

waitForElement();

Handling Timeouts

If the condition is not met within the timeout, a TimeoutError is thrown.

import { waitUntil, TimeoutError } from 'async-wait-until';

const waitForElement = async () => {
  try {
    const element = await waitUntil(() => document.querySelector('#target'), { timeout: 5000 });
    console.log('Element found:', element);
  } catch (error) {
    if (error instanceof TimeoutError) {
      console.error('Timeout: Element not found');
    } else {
      console.error('Unexpected error:', error);
    }
  }
};

waitForElement();

๐Ÿ“š API Reference

waitUntil(predicate, options)

Waits for the predicate function to return a truthy value and resolves with that value.

Parameters:

NameTypeRequiredDefaultDescription
predicateFunctionโœ… Yes-A function that returns a truthy value (or a Promise for one).
options.timeoutnumber๐Ÿšซ No5000 msMaximum wait time before throwing TimeoutError. Use WAIT_FOREVER for no timeout.
options.intervalBetweenAttemptsnumber๐Ÿšซ No50 msInterval between predicate evaluations.

Exported Constants

NameValueDescription
WAIT_FOREVERโˆžUse for infinite timeout (no time limit).
DEFAULT_TIMEOUT_IN_MS5000Default timeout duration in milliseconds.
DEFAULT_INTERVAL_BETWEEN_ATTEMPTS_IN_MS50Default interval between attempts in milliseconds.

Exported Classes

  • TimeoutError - Error thrown when timeout is reached before condition is met.

๐Ÿ”ง TypeScript Usage

This library is written in TypeScript and includes full type definitions. Here are some TypeScript-specific examples:

Basic TypeScript Usage

import { waitUntil, TimeoutError, WAIT_FOREVER } from 'async-wait-until';

// The return type is automatically inferred
const element = await waitUntil(() => document.querySelector('#target'));
// element is typed as Element | null

// With custom timeout and interval
const result = await waitUntil(
  () => someAsyncCondition(),
  { 
    timeout: 10000, 
    intervalBetweenAttempts: 100 
  }
);

Using with Async Predicates

// Async predicate example
const checkApiStatus = async (): Promise<boolean> => {
  const response = await fetch('/api/health');
  return response.ok;
};

try {
  await waitUntil(checkApiStatus, { timeout: 30000 });
  console.log('API is ready!');
} catch (error) {
  if (error instanceof TimeoutError) {
    console.error('API failed to become ready within 30 seconds');
  }
}

Type-Safe Options

import { Options } from 'async-wait-until';

const customOptions: Options = {
  timeout: 15000,
  intervalBetweenAttempts: 200
};

await waitUntil(() => someCondition(), customOptions);

๐Ÿ’ก Recipes

Wait Indefinitely

Use WAIT_FOREVER to wait without a timeout:

import { waitUntil, WAIT_FOREVER } from 'async-wait-until';

await waitUntil(() => someCondition, { timeout: WAIT_FOREVER });

Adjust Retry Interval

Change how often the predicate is evaluated:

await waitUntil(() => someCondition, { intervalBetweenAttempts: 1000 }); // Check every 1 second

Wait for API Response

const waitForApi = async () => {
  const response = await waitUntil(async () => {
    try {
      const res = await fetch('/api/status');
      return res.ok ? res : null;
    } catch {
      return null; // Keep trying on network errors
    }
  }, { timeout: 30000, intervalBetweenAttempts: 1000 });
  
  return response.json();
};

Wait for File System Changes (Node.js)

import fs from 'fs';
import { waitUntil } from 'async-wait-until';

// Wait for a file to be created
const filePath = './important-file.txt';
await waitUntil(() => fs.existsSync(filePath), { timeout: 10000 });

// Wait for file to have content
await waitUntil(() => {
  if (fs.existsSync(filePath)) {
    return fs.readFileSync(filePath, 'utf8').trim().length > 0;
  }
  return false;
});

Wait for Database Connection

const waitForDatabase = async (db) => {
  await waitUntil(async () => {
    try {
      await db.ping();
      return true;
    } catch {
      return false;
    }
  }, { timeout: 60000, intervalBetweenAttempts: 2000 });
  
  console.log('Database is ready!');
};

Wait with Custom Conditions

// Wait for multiple conditions
const waitForComplexCondition = async () => {
  return waitUntil(() => {
    const user = getCurrentUser();
    const permissions = getPermissions();
    const apiReady = isApiReady();
    
    // All conditions must be true
    return user && permissions.length > 0 && apiReady;
  });
};

// Wait for specific value ranges
const waitForTemperature = async () => {
  return waitUntil(async () => {
    const temp = await getSensorTemperature();
    return temp >= 20 && temp <= 25 ? temp : null;
  });
};

๐ŸŒ Browser Compatibility

This library works in any JavaScript environment that supports Promises:

Node.js: โœ… Version 0.14.0 and above
Modern Browsers: โœ… Chrome 32+, Firefox 29+, Safari 8+, Edge 12+
Legacy Browsers: โœ… With Promise polyfill (e.g., es6-promise)

CDN Usage

<!-- UMD bundle via CDN -->
<script src="https://unpkg.com/async-wait-until@latest/dist/index.js"></script>
<script>
  // Available as global variable
  asyncWaitUntil.waitUntil(() => document.querySelector('#target'))
    .then(element => console.log('Found:', element));
</script>

ES Modules in Browser

<script type="module">
  import { waitUntil } from 'https://unpkg.com/async-wait-until@latest/dist/index.esm.js';
  
  const element = await waitUntil(() => document.querySelector('#target'));
  console.log('Found:', element);
</script>

๐Ÿ” Troubleshooting

Common Issues

Q: My predicate never resolves, what's wrong?
A: Make sure your predicate function returns a truthy value when the condition is met. Common mistakes:

  • Forgetting to return a value: () => { someCheck(); } โŒ
  • Correct: () => { return someCheck(); } โœ… or () => someCheck() โœ…

Q: I'm getting unexpected timeout errors
A: Check that:

  • Your timeout is long enough for the condition to be met
  • Your predicate function doesn't throw unhandled errors
  • Network requests in predicates have proper error handling

Q: The function seems to run forever
A: This happens when:

  • Using WAIT_FOREVER without proper condition logic
  • Predicate always returns falsy values
  • Add logging to debug: () => { const result = myCheck(); console.log(result); return result; }

Q: TypeScript compilation errors
A: Ensure you're importing types correctly:

import { waitUntil, Options, TimeoutError } from 'async-wait-until';

Performance Tips

  • Use reasonable intervals (50-1000ms) to balance responsiveness and CPU usage
  • For expensive operations, increase the interval: { intervalBetweenAttempts: 1000 }
  • Implement proper error handling in async predicates to avoid unnecessary retries
  • Consider using WAIT_FOREVER with external cancellation for long-running waits

๐Ÿงช Development and Testing

Contributions are welcome! To contribute:

  1. Fork and clone the repository.
  2. Install dependencies: npm install.
  3. Use the following commands:
  • Run Tests: npm test
  • Lint Code: npm run lint
  • Format Code: npm run format
  • Build Library: npm run build
  • Generate Docs: npm run docs