Home > Blockchain >  Express.js - Pending promise blocks and delays next GET request in express (Node.js)
Express.js - Pending promise blocks and delays next GET request in express (Node.js)

Time:11-03

I have a running express application which listens for GET requests. Any GET request immediately returns a success response and runs a function asyncForLoop() which returns a promise which resolves after 5 seconds.

Problem: Even though asyncForLoop() gets called after res.json() any upcoming GET request afterwards gets delayed until the promise in asyncForLoop() gets resolved.

const express = require("express");
const app = express();

app.listen(3005, () => {
  console.log(new Date().getTime()   " running on port 3005.");
});

app.get("/*", (req, res) => {
  myResponse(req, res);
});

function myResponse(req, res) {
  console.log(new Date().getTime()   " GET request => "   req.originalUrl);

  res.json({ success: true });

  // this function blocks any following request until it is resolved
  asyncForLoop().then(res => {
    console.log(new Date().getTime()   " finished for-loop.");
  });
}

function asyncForLoop() {
  return new Promise(function(resolve, reject) {
    // simulate a long synchronous action using wait() in a for-loop
    for (let i=0; i<5; i  ) {
      console.log(i);
      wait(1000);
    }

    resolve();
  });
}

function wait(ms) {
  let start = Date.now(),
      now = start;
  while (now - start < ms) {
    now = Date.now();
  }
}

You can test the code above by running the script using node and opening two tabs with the address localhost:3005 in a browser. The first tab will immediately get a response while the second tab loads for 5 seconds.

Screencast

Question: Why does the promise inside asyncForLoop() delay upcoming requests? Shouldn't it be handled asynchronously because it's inside a promise? How can I prevent this delayed second request?

Thanks!

CodePudding user response:

JavaScript is single-threaded. A long running loop will block all your code. You can use an asynchronous wait function:

const express = require("express");
const app = express();

app.get("/*", (req, res) => {
  myResponse(req, res);
});

async function myResponse(req, res) {
  console.log(new Date().getTime()   " GET request => "   req.originalUrl);

  res.json({ success: true });

  await asyncForLoop();
  console.log(new Date().getTime()   " finished for-loop.");
}

async function asyncForLoop() {
  for (let i=0; i<5; i  ) {
    console.log(i);
    await wait(1000);
  }
}

function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

app.listen(3005, () => {
  console.log(new Date().getTime()   " running on port 3005.");
});
  • Related