Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
241 changes: 239 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ A lightweight, zero-dependency library for waiting asynchronously until a specif
![MIT License](https://img.shields.io/npm/l/async-wait-until)
[![Maintainability](https://api.codeclimate.com/v1/badges/2a967399786c0d306247/maintainability)](https://codeclimate.com/github/devlato/async-wait-until/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

- [Installation](#-installation)
- [How to Use](#️-how-to-use)
- [API Reference](#-api)
- [TypeScript Usage](#-typescript-usage)
- [Recipes](#-recipes)
- [Browser Compatibility](#-browser-compatibility)
- [Troubleshooting](#-troubleshooting)
- [Development and Testing](#-development-and-testing)
- [Links](#-links)

## 📖 Detailed Documentation

For detailed documentation, visit [https://devlato.github.io/async-wait-until/](https://devlato.github.io/async-wait-until/)
Expand All @@ -21,7 +43,7 @@ Install using npm:
npm install async-wait-until
```

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

```javascript
import { waitUntil } from 'async-wait-until';
Expand Down Expand Up @@ -73,7 +95,7 @@ waitForElement();

---

## 📚 API
## 📚 API Reference

### `waitUntil(predicate, options)`

Expand All @@ -87,6 +109,75 @@ Waits for the `predicate` function to return a truthy value and resolves with th
| `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

```typescript
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

```typescript
// 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

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

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

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

---

## 💡 Recipes
Expand All @@ -109,6 +200,152 @@ Change how often the predicate is evaluated:
await waitUntil(() => someCondition, { intervalBetweenAttempts: 1000 }); // Check every 1 second
```

### Wait for API Response

```javascript
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)

```javascript
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

```javascript
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

```javascript
// 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

```html
<!-- 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

```html
<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:
```typescript
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
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "async-wait-until",
"version": "2.0.29",
"version": "2.0.30",
"description": "Waits until the given predicate function returns a truthy value, then resolves",
"main": "./dist/index.js",
"module": "./dist/index.esm.js",
Expand Down