DEV Community

Krishna Bhamare
Krishna Bhamare

Posted on

Building async task queues and pub-sub architecture in JS.

Building an async task queue And pub-sub architecture in JS can be a great way to leverage Javascript concurrency model and performance.

1. Async Task Queue:

For an async task queue, you can use the async library, but let's build a simple one using native JavaScript promises and setTimeout.

Queue Implementation

class TaskQueue {
    constructor(concurrency) {
        this.queue = [];
        this.concurrency = concurrency;
        this.running = 0;
    }

    async runTask(task) {
        if (this.running >= this.concurrency) {
            await new Promise(resolve => this.queue.push(resolve));
        }
        this.running++;
        try {
            await task();
        } finally {
            this.running--;
            if (this.queue.length > 0) {
                this.queue.shift()();
            }
        }
    }

    addTask(task) {
        return this.runTask(task);
    }
}

// Usage example
const queue = new TaskQueue(2);

const createTask = (i) => () => new Promise((resolve) => {
    setTimeout(() => {
        console.log(`Task ${i} completed`);
        resolve();
    }, 1000);
});

for (let i = 1; i <= 5; i++) {
    queue.addTask(createTask(i));
}

Enter fullscreen mode Exit fullscreen mode

TaskQueue Class:

  • Constructor: Initializes the task queue with a maximum concurrency (this.concurrency) and a running count (this.running).
  • runTask(task): Handles executing tasks. If the number of currently running tasks reaches the concurrency limit, it waits (using a promise) until a slot becomes available. Once a task starts, it increments the running counter. After completing a task, it decrements the counter and checks if there are queued tasks waiting to be executed.
  • addTask(task): Adds a new task to the queue.

Usage Example:

  • createTask(i): A function that returns a task. Each task is a promise that resolves after 1 second and logs a message.
  • for Loop: Adds multiple tasks to the queue. The queue will process tasks based on the concurrency limit.

2. Pub-Sub Architecture:

A basic pub-sub system can be built using simple JavaScript objects. Subscribers register themselves to topics, and publishers send messages to these topics.
Pub-Sub Implementation

class PubSub {
    constructor() {
        this.topics = {};
    }

    subscribe(topic, listener) {
        if (!this.topics[topic]) {
            this.topics[topic] = [];
        }
        this.topics[topic].push(listener);
    }

    publish(topic, message) {
        if (this.topics[topic]) {
            this.topics[topic].forEach(listener => listener(message));
        }
    }
}

// Usage example
const pubsub = new PubSub();

pubsub.subscribe('news', (message) => {
    console.log(`Received message: ${message}`);
});

pubsub.publish('news', 'Hello World!');
pubsub.publish('news', 'Another message!');
Enter fullscreen mode Exit fullscreen mode

PubSub Class:

Constructor: Initializes an empty object to hold topics and their associated listeners.
subscribe(topic, listener): Adds a listener function to a topic. If the topic doesn’t exist, it creates a new array for it.
publish(topic, message): Iterates over all listeners for the given topic and calls them with the provided message.

Usage Example:

  • pubsub.subscribe('news', (message) => {...}): Subscribes to the 'news' topic with a listener that logs received messages.
  • pubsub.publish('news', 'Hello World!'): Publishes a message to the 'news' topic. All subscribed listeners will be notified with this message.

Summary

  • Async Task Queue: Managed with native JavaScript promises and concurrency control.
  • Pub-Sub Architecture: Uses plain JavaScript objects to manage topics and listeners.

Top comments (0)