Unfulfilled expectation of a promise within an array slipping through the cracks of a for loop

I have a function that generates a Promise. Afterward, I have another function that constructs an array of these promises for future utilization. It is important to note that I do not want to execute the promises within the array building function since sometimes I may need to invoke them in parallel using Promise.all(), and at other times I may need to call them sequentially within a for loop (as in this scenario).

The function that yields a promise appears as follows:

export const getQueue = async (
  date: string,
  hour: string,
  queue: Queue
) => {
  const queueDateTime = getDateTimeFromQueueDateHour(date, hour);
  try {

    // carry out asynchronous tasks..

    return { queue, queueDateTime };
  } catch (e) {

    // transform error into custom error

    if (e instanceof Error) {
      throw new GetQueueError(queue, queueDateTime, e.message);
    } else {
      throw e;
    }
  }
};

Subsequently, my function for creating an array of promises looks like this (QUEUE_IDS is a constant imported from elsewhere):

export const getAllQueues = (
  date: string,
  hour: string
) => {
  const queuePromises: Promise<{
    queue: string;
    matchCount: number;
    queueDateTime: DateTime;
  }>[] = [];
  for (const queue in QUEUE_IDS) {
    queuePromises.push(
      getQueue(date, hour, queue as Queue)
    );
  }

  return queuePromises;
};

Finally, the job function that utilizes the function for generating the promise array is presented below:

const matchHistoryJobFn: JobFn<MatchQueueSuccess> = async (jobId, jobKey) => {
  try {

    // ...

    const queues = getAllQueues(
      dateTimeToGetQueueDate(lastMatchIdQueueDate),
      "-1"
    );

    let matchCount = 0;

    for (let i = 0; i < queues.length; i++) {
      try {
        const q = await queues[i];
        matchCount += q.matchCount;
      } catch (e) {
        if (e instanceof GetQueueError) {
          log({
            jobId,
            jobKey,
            status: "error",
            message: e.message,
            currentDateTime: DateTime.utc().toISO(),
            meta: { queueDate: e.queueDateTime.toISO(), queue: e.queue },
          });
        } else {
          log({
            jobId,
            jobKey,
            status: "error",
            message: e as string,
            currentDateTime: DateTime.utc().toISO(),
          });
        }
      }
    }

    // ...

    return {
      jobId,
      meta: { queueDate: lastMatchIdQueueDate.toISO(), matchCount },
    };
  } catch (e) {
    throw handleJobError(e, jobId);
  }
};

In the for loop, I aim to capture any errors occurring with particular queues so that processing can continue with other queues unaffected. Unfortunately, my application keeps crashing due to an unhandled exception originating from 'getQueue'. I am unable to comprehend why this occurs since not only is the invocation of await queue[i] enclosed in a try-catch block, but the entire job function is also wrapped in its own try-catch.

Edit: On a side note, upon inspecting with the VS Code debugger, it is clear that the error is indeed being thrown by getQueue and not being captured within the for loop.

Answer №1

I am curious about why the error is not caught in the try catch block at the point of await. Interestingly, using array functions seems to have resolved the issue for me.

The primary concern lies in how node.js detects an unhandled rejection. When your code initiates a promise-based asynchronous operation without immediately assigning a .catch() handler, it can lead to unhandled rejections. For instance, while your code waits at an await statement, another promise may reject without being caught by an await or try/catch on that specific promise yet, resulting in an unhandled rejection.

Consider the following code snippet:

const queues = getAllQueues(
  dateTimeToGetQueueDate(lastMatchIdQueueDate),
  "-1"
);

This call triggers all the getQueue() functions simultaneously, creating an array of promises linked to ongoing asynchronous operations. At this stage, there are no catch handlers for these promises that might reject.

Subsequently, you process each queue one at a time using await. The await command suspends execution until the first promise fulfills, leaving other promises vulnerable to rejection if not awaited with appropriate error handling. Node.js interprets such scenarios as unhandled rejections since the program is perceived to be waiting for an await fulfillment without proper error handling in place.

To avoid such issues, ensure every promise has a corresponding .catch() handler before awaiting its resolution and refrain from leaving promises unresolved when returning to the event loop.


If your objective is to prevent running asynchronous operations in parallel, consider restructuring your code to execute them sequentially. Instead of calling all getQueue() functions at once within getAllQueues(), opt to invoke them one after the other. One approach could involve building an array of promise-returning functions and calling them serially within a loop while awaiting each one. Alternatively, create a function specifically designed to call getQueue() sequentially, await each invocation, and return a promise containing an array of outcomes.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Conceal content upon clicking with JavaScript

Showing a form after clicking a link can be achieved using this code: $(function () { $('.msg').on('click', function (e) { e.preventDefault(); $(this).next('.msgarea').show(); }); }); <a href="" cl ...

Change the URL structure from ex.com/forum?id=1 to ex.com/#/forum?id=1 in AngularJS

Hey there! I'm in the process of creating a Forum using AngularJS and need some guidance. First things first! I've successfully established a connection to my database with: <?php session_start(); $db = new mysqli("localhost","root",""," ...

What is the best way to concatenate a data object?

This task should be quite straightforward. Using Vanilla JS, I am trying to update the content of a span element with the session ID obtained from a function call. Here's an example: sessionId = 0_77b1f7b5-b6c8-49a0-adbc-7883d662ebba document.getEle ...

The AJAX request successfully retrieves data, but the page where it is displayed remains empty

I have come across similar questions to mine, but I have not been successful in implementing their solutions. The issue I am facing involves an AJAX call that is functioning correctly in terms of receiving a response. However, instead of processing the re ...

Exploring the process of navigating through jQuery Arrays: Utilizing JQuery Array Filter

I need help finding a way to SEARCH through a jQuery array or object. I'm not looking to just check if the value is in the array, but to search for related terms based on user input. It's similar to how we filter ArrayList in Java or use SQL LIKE ...

having trouble with npm installation of firebase-tools

I am encountering an issue while attempting to set up firebase-tools for my android studio project. Here is the error message that I am facing: Microsoft Windows [Version 10.0.15063] (c) 2017 Microsoft Corporation. All rights reserved. C:\WINDOWS&bs ...

Unexpected behavior is being encountered with the else statement, and there are compatibility issues with IE and Mozilla Browser in the overall script

Script is functioning as expected in Google Chrome, but is not responsive in IE and Mozilla browsers JavaScript code: <script src="jquery.min.js"></script> <script> function Run() { if(jQuery('#inputtext').val() == '0 ...

IE may not support the use of XMLHttpRequest with the POST method

When interacting with a server through an XMLHttpRequest to post data, the code typically follows this structure: var xhr = new XMLHttpRequest(); var url = 'http://myurl/post'; xhr.open("POST", url, true); xhr.setRequestHeader("Content-type", " ...

Obtain the specific key's value from a new Map state

In my code, I've defined a variable called checkedItems as a new Map(); When I try to console.log(checkedItem), the output is as follows: Map(3) {"1" => true, "1.5" => true, "2" => false} Is there a way ...

The content loses functionality once I add an overlay color to the background image div

I'm facing an issue with a div that has a background image, text, and a button in the center. Whenever I add an overlay color on top of the background image, the text and button seem to be disabled or unclickable. My goal is to ensure that the Read M ...

The functionality of the Youtube API is compromised when adjusting display settings on mobile devices

I've successfully embedded a YouTube player using the js-api, and it's working perfectly. However, I don't want the player to be visible by default. To achieve this, I placed the player inside a div with 'display:none;' set. When I ...

Efficient Loading and Smooth Scrolling with Angular2 (version 7)

I'm struggling to display a component upon the initial page load using lazy loading, where the content is only loaded when it's in view. For instance: - With 10 components on the page, I aim to show/scroll to component number 7 when the page lo ...

Automate table column width adjustments in HTML using Selenium WebDriver

As of now, I am working on automating the process of increasing the width of an HTML table column using Selenium WebDriver. I discovered that I can retrieve the coordinates of x and y by using findElement(By.cssSelector("<Css locator>").getLocation( ...

Is it possible to place Angular Material components using code?

Currently, I'm in the process of creating a responsive Angular application. Is there any way to adjust the height and position of the <mat-sidenav-content></mat-sidenav-content> component in Angular Material programmatically without relyi ...

Next.js directs API requests to the root URL

I'm currently working with an API handler pages/api/[slug]/[uid].ts My goal is to redirect the requests to the main root of my application, specifically: http://localhost:3000/[slug]/[uid] What steps do I need to take in next.config in order to mak ...

The div has extra white space at the bottom due to the Hide/Show content feature

Having trouble stretching a scrolling div to 100% of its parent container's height? The Hide/Show content feature is causing whitespace at the bottom of the div. Check out the jsfiddle here: http://jsfiddle.net/fkvftff2/1/ LATEST UPDATE: The issue a ...

Swapping out the JSON data from the API with HTML content within the Vue.js application

I am currently working on a project involving Vite+Vue.js where I need to import data from a headless-cms Wordpress using REST API and JSON. The goal is to display the titles and content of the posts, including images when they appear. However, I have enco ...

Generating fresh line with knockout effect

Currently in the process of developing a Single Page Application (SPA). Utilizing knockout and observable array to iterate through a json array. Encountering an issue where there are br tags present within the text, but when using data-bind="text: myVar" ...

It appears that the ngOnInit function is being activated prior to receiving any data through the Input()

For a personal challenge, I am working on creating a website that showcases a list of League Of Legends champions. Users can click on the champion icons to access more details. However, I am facing an issue where the champion details (specifically images) ...

The art of replacing material-ui styles with styled components

As a newcomer to UI material design, I am eager to create my own customized Button Component using styled-components. I am facing a challenge in overriding the CSS based on different button variations such as "primary" or "secondary". You can find my cod ...