JavaScript
TypeScript
Asynchronous Programming
Async/Await
Bounded Queue

Asynchronous Bounded Queue in JS/TS using async/await

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

In JavaScript and TypeScript, concurrency is often handled in a single-threaded environment. To manage the asynchronous flow of data and tasks, JavaScript provides several constructs including Promises and async/await. One useful pattern that arises when managing concurrent tasks is the Asynchronous Bounded Queue. This article will explore the Asynchronous Bounded Queue pattern using async/await and discuss its potential applications in JavaScript/TypeScript development.

Understanding the Asynchronous Bounded Queue

An Asynchronous Bounded Queue is a data structure that controls access to a queue with a limited size, ensuring that no more than a predefined number of items are in the queue at any one time. This is particularly useful for managing resource usage, such as limiting the number of concurrent downloads, API requests, or processing tasks.

Key Characteristics

  • Bounded Size: The queue has a maximum capacity. If the queue is full, new attempts to add items must wait until there is space available.
  • Concurrency Control: Manage and limit concurrent tasks effectively, ensuring efficient usage of system resources.
  • Asynchronous Operations: Leverage JavaScript's async/await syntax to handle enqueue and dequeue operations.

Basic Implementation

Here is an example of an Asynchronous Bounded Queue implemented in TypeScript using async/await:

typescript
1class AsyncBoundedQueue<T> {
2  private queue: T[] = [];
3  private resolveQueue: (() => void)[] = [];
4  private capacity: number;
5
6  constructor(capacity: number) {
7    this.capacity = capacity;
8  }
9
10  async enqueue(item: T): Promise<void> {
11    if (this.queue.length >= this.capacity) {
12      await new Promise<void>(resolve => this.resolveQueue.push(resolve));
13    }
14    this.queue.push(item);
15  }
16
17  async dequeue(): Promise<T> {
18    while (this.queue.length === 0) {
19      await new Promise<void>(resolve => this.resolveQueue.push(resolve));
20    }
21    const item = this.queue.shift()!;
22    if (this.resolveQueue.length > 0) {
23      this.resolveQueue.shift()!();
24    }
25    return item;
26  }
27}

Enqueue and Dequeue Operations

  • Enqueue: If the queue is full, the enqueue method returns a Promise that resolves only when there is space in the queue.
  • Dequeue: If the queue is empty, the dequeue method returns a Promise that resolves only when an item is available to dequeue.

Practical Applications

The Asynchronous Bounded Queue is ideal for scenarios where resource constraints must be respected. Here are a few examples:

  1. Rate Limiting API Requests: Control the number of concurrent HTTP requests to an API within the allowed limits.
  2. Batch Processing: Manage tasks that need to process data in batches, like image processing or database updates.
  3. Task Scheduling: Coordinate concurrent tasks in a system that performs actions like I/O operations, computational tasks, or interactions with external services.

Example: Rate Limiting API Requests

typescript
1async function fetchWithRateLimiting(url: string, queue: AsyncBoundedQueue<() => Promise<any>>): Promise<any> {
2  return new Promise((resolve, reject) => {
3    queue.enqueue(async () => {
4      try {
5        const response = await fetch(url);
6        resolve(await response.json());
7      } catch (error) {
8        reject(error);
9      } finally {
10        queue.dequeue();
11      }
12    });
13  });
14}
15
16const queue = new AsyncBoundedQueue<() => Promise<any>>(5); // Limit to 5 concurrent requests
17
18async function makeRequests(urls: string[]) {
19  const promises = urls.map(url => fetchWithRateLimiting(url, queue));
20  return Promise.all(promises);
21}

Summary Table

Here's a quick summary of key points related to Asynchronous Bounded Queue:

FeatureDescription
CapacityMaximum number of items that the queue can hold.
EnqueueAdds an item to the queue; waits if the queue is full.
DequeueRemoves an item from the queue; waits if the queue is empty.
Concurrency ControlLimits concurrent execution of tasks.
Use CasesRate limiting API requests, batch processing, task scheduling.
ImplementationLeverages async/await for seamless integration with asynchronous code.

Conclusion

The Asynchronous Bounded Queue is a powerful construct for managing concurrency in JavaScript and TypeScript. By controlling the number of concurrent tasks and efficiently handling asynchronous operations, developers can optimize resource use and improve system stability. With a solid understanding of queues and async/await, you can leverage this pattern in a wide array of applications involving asynchronous data flows and task management in modern web development.


Course illustration
Course illustration

All Rights Reserved.