Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

devlato/async-wait-until

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

270 Commits

Repository files navigation

async-wait-until

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:

Name Type Required Default Description
predicate Function βœ… Yes - A function that returns a truthy value (or a Promise for one).
options.timeout number 🚫 No 5000 ms Maximum wait time before throwing TimeoutError. Use WAIT_FOREVER for no timeout.
options.intervalBetweenAttempts number 🚫 No 50 ms Interval between predicate evaluations.

Exported Constants

Name Value Description
WAIT_FOREVER ∞ Use for infinite timeout (no time limit).
DEFAULT_TIMEOUT_IN_MS 5000 Default timeout duration in milliseconds.
DEFAULT_INTERVAL_BETWEEN_ATTEMPTS_IN_MS 50 Default 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

πŸ“ Links

Sponsor this project

Contributors 5

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /