Interview Question: Priority Queue for Promises in JavaScript
Tags: javascript, interview, tutorial, webdev
Published: 2023-11-08 05:30:00

# Implementing a Priority Queue for Promises in JavaScript

Imagine a scenario where you have a list of promises, and you want to get the result of the first resolved promise. If the first promise is rejected, you'd like to ensure that the function returns the result of the next resolved promise. And, in the worst-case scenario where all promises are rejected, you want to gather a list of errors. In this blog post, we'll discuss how to implement a priority queue for promises in JavaScript to achieve this.

## The Problem

Consider the following example:

```javascript
const resolveIn = (time) => new Promise((resolve) => setTimeout(() => resolve(time), time));
const rejectIn = (time) => new Promise((_, reject) => setTimeout(() => reject(time), time));

const firstResolved = async (promises) => {
  // Your solution goes here
};

const promises1 = [rejectIn(1000), resolveIn(500), resolveIn(20000)];
const result1 = await firstResolved(promises1);
console.log(result1); // 500 (after 1000ms)

const promises2 = [rejectIn(1000), resolveIn(5000), resolveIn(100)];
const result2 = await firstResolved(promises2);
console.log(result2); // 5000 (after 5000ms)
```

In this example, we have an array of promises. The `firstResolved` function should return the first resolved promise, and if the first promise is rejected, it should return the next resolved promise. If all promises are rejected, it should return a list of errors.

## Solution Overview

To implement this behavior, we need to execute all promises in parallel, similar to running a race. We cannot use `Promise.all` because it would reject the entire operation if any promise is rejected. Also, we don't want to wait for the last promise to resolve; we want to return the result as soon as possible. The same issue applies to `Promise.allSettled`.

`Promise.any` is a good candidate for this operation. It returns the first resolved promise but in the second example, it returns the result of the last promise because it's the first resolved promise. This is not the behavior we want.

Let's implement a custom solution to handle this priority queue for promises.

## The Implementation

```javascript
const firstResolved = (promises) => {
  if (!promises || !promises.length)
    return Promise.reject("No promises provided");

  const results = Array(promises.length).fill(null);

  return new Promise((resolve, reject) => {
    const checkResults = () => {
      for (let i = 0; i < results.length; i++) {
        if (results[i] === null) return;
        if (results[i].status === "resolved") return resolve(results[i].value);
      }
      reject(results);
    };

    promises.forEach((promise, i) => {
      Promise.resolve(promise).then((result) => {
          results[i] = { status: "resolved", value: result };
        }).catch((error) => {
          results[i] = { status: "rejected", reason: error };
        }).finally(checkResults);
    });
  });
};
```

Here's how the solution works:

1. We first check if any promises are provided. If not, we reject the operation with an appropriate message.

2. We create an array called `results` with the same length as the number of promises. This array will store the status and value of each promise.

3. We return a new promise that handles the resolution and rejection logic.

4. The `checkResults` function is responsible for checking the status of the promises. It looks through the `results` array and immediately resolves the promise when it finds the first resolved promise. If all promises are rejected, it rejects the operation with the collected error information.

5. We iterate through the promises using a `forEach` loop. For each promise, we attach `then`, `catch`, and `finally` handlers. The `then` handler updates the `results` array with the resolved value, the `catch` handler updates it with the rejection reason, and the `finally` handler calls `checkResults`.

With this implementation, the function will return the result of the first resolved promise or a list of errors if all promises are rejected.

## Testing the Implementation

Let's test the `firstResolved` function with the examples we discussed earlier.

```javascript
const promises1 = [rejectIn(1000), resolveIn(500), resolveIn(20000)];
const result1 = await firstResolved(promises1);
console.log(result1); // 500 (after 1000ms)

const promises2 = [rejectIn(1000), resolveIn(5000), resolveIn(100)];
const result2 = await firstResolved(promises2);
console.log(result2); // 5000 (after 5000ms)
```


Thanks for reading! I hope you enjoyed this article. Feel free to share your thoughts in the comments below.


---

##### Must Read If you haven't

###### [3 steps to create custom state management library with React and Context API](https://dev.to/devsmitra/3-steps-to-create-custom-state-management-library-with-react-hooks-and-context-api-1bfh)

###### [How to cancel Javascript API request with AbortController](https://dev.to/devsmitra/how-to-cancel-javascript-api-request-with-abortcontroller-36cm)

###### [Getting started with SolidJs – A Beginner's Guide](https://dev.to/devsmitra/getting-started-with-solidjs-a-beginners-guide-5af4)

---

###### More content at [Dev.to](https://dev.to/devsmitra "Rahul Sharma(DevsMitra)").

{% user devsmitra %}

###### Catch me on
<p>
{% cta https://www.youtube.com/@bit-buddy?sub_confirmation=1 %} Youtube {% endcta %}
{% cta https://github.com/devsmitra %} Github {% endcta %}
{% cta https://www.linkedin.com/in/rahul-sharma-18b8b374 %} LinkedIn {% endcta %}
{% cta https://devsmitra.medium.com %} Medium {% endcta %}
{% cta https://stackblitz.com/@devsmitra %} Stackblitz {% endcta %} {% cta https://devsmitra.hashnode.dev %} Hashnode {% endcta %}
{% cta https://hackernoon.com/u/devsmitra %} HackerNoon {% endcta %}
</p>