ykensuke9 ykensuke9 - 5 months ago 22
Node.js Question

Why express on Node.js processes http requests "serially"?

I tried below two codes. I just accessed these programs from two browsers at the same time.

In Sample1, res.send is executed after all processings and which is general implementation.
I mean, these "setTimeout" can be database access or something like that.

In Sample2, res.send is executed at first, and after that, the rest of processings happen.

According to the output of Sample1, every http requests are processed serially. So if some people access this website at the same time, they need to wait for every prior people.
At first, I thought the reason is because Node.js processes everything serially. But I noticed it's wrong understanding according to the result of Sample2.
From the result, Node.js can simultaneously process some bunch of functions which include non-blocking code like setTimeout.

So I can't understand why express is implemented such a way.
As a result, we need to use Cluster with like PM2 to process some http request at the same time.

Could you teach me why express behaves such a way? And the only solution to process some http requests at the same time is just using Cluster?

Sample1

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

app.get('/', function (req, res) {
var id = Math.floor(1000*Math.random())
console.log('0 - ' + id)
setTimeout(()=>{
console.log('1 - ' + id)
setTimeout(()=>{
console.log('2 - ' + id)
setTimeout(()=>{
console.log('3 - ' + id)
res.send('Hello World!');
}, 1000)
}, 1000)
}, 1000)
});

app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});


Output of Sample1

0 - 957
1 - 957
2 - 957
3 - 957
0 - 447
1 - 447
2 - 447
3 - 447


Sample2

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

app.get('/', function (req, res) {
res.send('Hello World!');
var id = Math.floor(1000*Math.random())
console.log('0 - ' + id)
setTimeout(()=>{
console.log('1 - ' + id)
setTimeout(()=>{
console.log('2 - ' + id)
setTimeout(()=>{
console.log('3 - ' + id)
}, 1000)
}, 1000)
}, 1000)
});

app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});


Output of Sample2

0 - 902
0 - 742
1 - 902
1 - 742
2 - 902
2 - 742
3 - 902
3 - 742

Answer

It may be because of your browser as described here

I just tested it with Sample1 and curl by using

for i in $(seq 1 5); do curl localhost:3000/ & done  

to fire 5 requests and I saw them running concurrently - see the GIF.
So I do not think that express is serializing your requests but your client.

enter image description here

BTW: In my output there is an additional 3rd column showing Date.now() for each log line as my initial guess was it is because of buffering the log output.