2

Full Disclosure: I am a nodeJS beginner.

Purpose: Test NodeJS express handling multiple requests at the same time, while being blocked on a promise, by using async-await.

Test Strategy: Create a simple nodeJS express server with async get. Open two browser tabs calling the same port. Despite async, both the browser requests are handled sequentially.

Code:

const express = require('express')

const app = express()

var i=0;

async function sleep(ms) {
    console.log("inside sleep now")
    return new Promise((resolve) => {
        setTimeout(resolve, ms)
    });
}


app.get('', async (req, res) => {
    i++
    console.log('Got new request. i count:' + i)
    console.log('Thread i:' + i + ' starting to sleep')
    await sleep(10000).then((resolve) => {
        console.log('I am resolved now')
        res.send('Hello Express')
    })
    console.log('Thread i:' + i + ' awake from sleep')

})

Observed Result: Despite async await, when I open the second browser with the tab, until the first thread is awake, I don't see the request logs for the second browser request.

Question: What am I missing? Can express not handle two browser request at the same time, while being blocked on promise, despite async-await. I must be missing something because I know that nodeJS while being single threaded can handle multiple requests by optimising wait time.

SnoopyMe
  • 1,015
  • 1
  • 12
  • 21
  • The answer [below](https://stackoverflow.com/a/67475639/6243352) is correct that this code is nonblocking but doesn't explain why you're seeing the observed behavior. See [Node Express does not handle parallel requests](https://stackoverflow.com/questions/63681851/node-express-does-not-handle-parallel-requests?rq=1) for the likely reason, which is that the client is stalling on subsequent requests. Try two different browsers instead of different tabs in the same browser and it should be parallel. – ggorlen May 12 '21 at 13:57
  • @esqew thanks, but that doesn't answer the question. [Node Express does not handle parallel requests](https://stackoverflow.com/questions/63681851/node-express-does-not-handle-parallel-requests?rq=1) should be the correct dupe target. – ggorlen May 12 '21 at 13:58

1 Answers1

1

None of your use of async/await makes sense. All of them can go.

  1. The use in your sleep() function is unnecessary because if you're not useing await, don't declare the function as async. async/await only makes sense when used in pairs.
  2. The use in your app.get handler is unnecessary because if you're already using .then() to wait for a promise, you don't need await on top of it. And if you're not using await, see #1.

With the fluff removed, what remains of your code is this:

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

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

app.get('/', (req, res) => {
    sleep(10000).then(() => res.send('Hello Express'));
});

Promises do not block. They register a callback, and program execution moves on immediately.

The above code handles concurrent requests just fine. All that sleep().then() does is register a callback and move on. After 10 seconds, the timeout hits, node runs the registered callback () => res.send('Hello Express'), and that's it. At no point any of this is blocking.


You could rewrite the above to

app.get('/', async (req, res) => {
    await sleep(10000);
    res.send('Hello Express');
});

and nothing would change.

await does not block. It registers a callback (of sorts), and program execution moves on immediately.

From inside a function that uses await it looks like blocking. From outside, it does not. Program execution never stops.

await puts a bookmark after sleep(10000) and immediately gives back control to node's main event loop. After 10 seconds, the timeout hits and node continues the function execution at the bookmarked place, running res.send('Hello Express') next. At no point any of this is blocking.

Tomalak
  • 332,285
  • 67
  • 532
  • 628