Unusual results observed with the Promise.all method

There's a code snippet I'm working on where I need to await 5 promises, wait for 2 seconds, and then continue with another set of 5 promises. However, it seems like the two instances of Promise.all are not being awaited as expected. I wonder if I have misunderstood the concept of Promise.all or if there is something missing in my code.

(function () {
    let val = 0

    const promiseArr = []
    for (let i = 0; i < 10; i++) {
        promiseArr[i] = new Promise((res) => {
            val += 500
            setTimeout((val2) => {
                console.log(val2)
                res()
            }, val, val)
        })
    }

    console.log();
    (async function() {
        await Promise.all(promiseArr.slice(0, 5))
        console.log('start await')
        await new Promise((res) => setTimeout(res, 2000))
        console.log('done await')
        await Promise.all(promiseArr.slice(6, 10))
    })()
}) ()

Expected output:

500
...
2500
start await
done await
3000
...
5000

Actual output:

500
1000
1500
2000
2500
start await
3000
3500
4000
4500
done await
5000

EDIT: After some more investigation, I realize why it behaves this way. It seems like I had a misunderstanding about an important concept involving Promises. Thanks for all the help provided!

Answer №1

If you're wondering why this message is displayed, it's because promises start executing as soon as they are created (or at the end of the current synchronous block), not when they are awaited.

To gain clarity, try organizing your code to log timestamps for each event:

const t0 = +new Date();

const logWithTime = (message = "") =>
  console.log("" + Math.round(+new Date() - t0) + ": " + message);

(async function() {
  let val = 0;

  const resolver = res => {
    val += 500;
    const thisVal = val; 
    logWithTime("Creating timeout for " + thisVal);
    setTimeout(
      arg => {
        logWithTime("Timeout for " + thisVal);
        res();
      },
      thisVal,
      thisVal,
    );
  };

  const promiseArr = [];
  for (let i = 0; i < 10; i++) {
    promiseArr[i] = new Promise(resolver);
  }

  logWithTime("awaiting for first 5...");
  await Promise.all(promiseArr.slice(0, 5));
  logWithTime("waiting for 2 seconds...");
  await new Promise(res => setTimeout(res, 2000));
  logWithTime("waiting for the rest...");
  await Promise.all(promiseArr.slice(6, 10));
  logWithTime("all done");
})();

This will output:

0: Creating timeout for 500
10: Creating timeout for 1000
10: Creating timeout for 1500
10: Creating timeout for 2000
10: Creating timeout for 2500
10: Creating timeout for 3000
10: Creating timeout for 3500
10: Creating timeout for 4000
10: Creating timeout for 4500
10: Creating timeout for 5000
10: awaiting for first 5...
511: Timeout for 500
1011: Timeout for 1000
1515: Timeout for 1500
2013: Timeout for 2000
2510: Timeout for 2500
2511: waiting for 2 seconds...
3010: Timeout for 3000
3512: Timeout for 3500
4011: Timeout for 4000
4511: Timeout for 4500
4511: waiting for the rest...
5011: Timeout for 5000
5011: all done

The order in which the timeouts are resolved can be observed clearly through these logs.

Answer №2

The countdown begins as soon as you execute the setTimeout function, not when you wait for the promise it returns to be resolved.

When the code

(res) => setTimeout(res, 2000)
is triggered, there are already 4 other pending setTimeouts that will complete and trigger the console.log before this one resolves.

Answer №3

It became apparent to me that I was also mistaken about this: when you create a Promise, its function is immediately executed. To achieve what you intended, you should create an array of functions and call them as required.

(function () {
    let value = 0

    const promiseArray = []
    for (let i = 0; i < 10; i++) {
        promiseArray[i] = () => new Promise((resolve) => {
            value += 500
            setTimeout((newValue) => {
                console.log(newValue)
                resolve()
            }, value, value)
        })
    }

    console.log();
    (async function() {
        await Promise.all(promiseArray.slice(0, 5).map((func) => func()))
        console.log('beginning await')
        await new Promise((resolve) => setTimeout(resolve, 2000))
        console.log('await finished')
        await Promise.all(promiseArray.slice(6, 10).map((func) => func()))
    })()
}) ()

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

Managing extensive geographical information through HTTP

What is the most efficient way to transmit a substantial volume of map information via HTTP for rendering on the client side? There must be a more effective approach than simply transmitting a JSON file containing all map data. I am interested in how maj ...

Having trouble fetching configuration values with Vue.js

console.log(process.env.test); displays "undefined" in the console. In the dev.env.js file, I have the following configuration. Do you see anything that I might have overlooked? 'use strict' const merge = require('webpack-merge') con ...

What is the procedure for obtaining a list of items with the second item marked as "true"?

Can you please provide guidance on how to iterate through a list of addresses (address object) where the object has the property "def" set to true? Here is an example response from an API request: { "status": true, "rspa": ...

Utilize Google Place Autocomplete to restrict input to only addresses recommended by autocomplete suggestions

My application includes an input field for users to enter an address, with the help of Google's Place Autocomplete feature for address suggestions. The location field is mandatory. I aim to restrict users from submitting the form with an address that ...

Create a file object using content with the help of JavaScript

I am working with a file containing specific data const ics = 'BEGIN:VCALENDAR\n' + 'VERSION:2.0\n' + 'CALSCALE:GREGORIAN\n' + 'METHOD:PUBLISH\n' + 'END:VCALENDAR\n'; I am trying t ...

Store the data from the form into the database according to the radio button choice

I feel like a fish out of water here...freshly dipping my toes into the ASP.net world, but finding it quite fascinating so far. Let me begin at the starting line: Background: I am currently working on an ASP.net MVC5 application that involves user login ...

The three.js animation fails to load on Github Pages

I have encountered an issue with my website. It runs smoothly when I use "parcel index.html" locally, but once I post it to Github pages, the JavaScript animation does not display. Upon checking the browser console, I see no errors. Can anyone provide guid ...

Learn the process of sending both Header and Body data in a POST request using Axios with Vue.js

I'm currently attempting to call the post API of AWS Cognito's Token endpoint. The API functions perfectly when tested in my Postman client, but I am encountering issues when implementing it in my VueJS code. Here is a snippet of my code: test. ...

The automatic opening of a modal in a Livewire component is not functioning as expected

I am having trouble displaying a modal when my component initializes. I have tried using $this->emit('show) to open the modal When I add a button in my view, the emit('show') works! However, I want the modal to be automatically shown whe ...

unable to retrieve controls generated from AJAX response

My web development stack includes ASP.NET C# with AJAX Professional (http://www.ajaxpro.info) 1) I am working on a scenario where I have a div container that holds a Panel control which should contain a dynamically generated DropDownList done in the codeb ...

Tips on coding javascript within an MVC4 C# environment

I am currently working with MVC 4 and facing an issue where I have the same action name for multiple views. This makes it difficult to write JavaScript code in all pages individually. Can I simply write the JavaScript in the C# action result instead? I at ...

extract the information from a specific div on a different website using JavaScript

My goal is to load a specific div with a class="container" from a website and extract its content into my application. Upon making an ajax call to retrieve the site's data, I encountered a cross-domain origin error since I don't have access to t ...

Monitor the number of clicks (conversions) on Google Adwords

On my website, I have a contact form and I would like to keep track of how many people click on it and gather information similar to what Google analytics provides. Here is what I want the form to do: When the button is clicked Ensure that all fields are ...

What steps can I take to ensure my dashboard table is dynamic, updates in real-time, and automatically reflects changes made in my MySQL database

FrontEnd Code import React, { Component, useState, useEffect } from "react"; import Navbar from "../Navbar/Navbar.js"; import BarChart from "../BarChart/BarChart"; import { Chart, Tooltip, CategoryScale, LinearScale, ...

What could be causing issues with my JavaScript AJAX?

I'm in the process of developing a basic chat system that automatically loads new messages as they come in. Initially, I used to fetch all messages from the database. However, I encountered an issue where the scroll bar would constantly jump to the bo ...

Converting a comma-separated string into an array of integers using jQuery

Is there a way in jQuery to convert a string containing multiple numbers into an array? The string in question is as follows: let values = "901,235,342,421,345,745,544,324,445,123,232,986,345,678"; ...

Continue running the remaining part of the function once the asynchronous function has completed its execution

To obtain the last 4 digits of a payment using Stripe, I need to execute an async function that contains another async function. Once these functions are resolved, I aim to update the database with the last four digits. It is crucial to ensure that the dat ...

Issue with React application and nginx configuration causing components not to switch when using router functionality

I have encountered an issue while trying to deploy my React app using nginx. The problem I am facing is that when I change routes, for example to /about, the front end does not update and remains on the index page. Here is the configuration in sites-avai ...

Issue with Material-UI tab not showing the component upon page load

After setting up material-ui tabs with react-router, I encountered an issue where only the tab names Tab A and Tab B are displayed upon page render. The desired behavior is for the TabAReport component to be automatically rendered without requiring user in ...

What is the best way to cut strings in JavaScript or jQuery?

Can anyone provide guidance on how to trim using this code? $('#type_of_station').text() Here is the result: >>> $('#type_of_station').text() "pizza delivery system " It appears that there is a space after the last word in ...