Skip to content

Instantly share code, notes, and snippets.

@ghaiklor
Created March 25, 2016 18:44
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save ghaiklor/9682b79353aade8a1e59 to your computer and use it in GitHub Desktop.
Save ghaiklor/9682b79353aade8a1e59 to your computer and use it in GitHub Desktop.
This example shows how you can block event loop in NodeJS
'use strict';
// The purpose of this example is to show
// how you can block the event loop with JavaScript.
// There is 3 routes
// / respond with Hello, World text
// /block uses JavaScript while for 5 seconds
// /non-block uses setTimeout for 5 seconds
// Do the following
// curl localhost:3000/
// You get Hello, World
// curl localhost:3000/block and curl localhost:3000/ at once
// your server is blocked now, because of while in JavaScript
// JavaScript code is executed in the main thread, where event loop
// that's why it blocks, because of while execution
// curl localhost:3000/non-block and curl:localhost:3000/ at once
// you will get Hello, World and after 5 seconds I am done
// in this case you don't block the server
// because operation thrown in thread-pool
// freeing the main thread for other connections
const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello, World'));
app.get('/block', (req, res) => {
const end = Date.now() + 5000;
while (Date.now() < end) {
const doSomethingHeavyInJavaScript = 1 + 2 + 3;
}
res.send('I am done!');
});
app.get('/non-block', (req, res) => {
// Imagine that setTimeout is IO operation
// setTimeout is a native implementation, not the JS
setTimeout(() => res.send('I am done!'), 5000);
});
app.listen(3000, () => console.log('app listening on port 3000'));
@aarshpatel
Copy link

Great Example!

@PaulWieland
Copy link

What if you have an async function that you want to wait for in your loop?

@ghaiklor
Copy link
Author

ghaiklor commented Aug 5, 2019

@PaulWieland async functions uses the Promise API under the hood, so you can await for some asynchronous functions and it will not block the others.

@minh-nguyen-hs
Copy link

@ghaiklor, As I know the Promise will execute in a separate thread so I try to convert the blocking process to use Promise. However, it still blocks the Event Loop. Could you please help me to explain why and how to resolve this problem?

function doHeavyTask() {
  log('Begin heavy task');
  return new Promise((resolve) => {
    const end = Date.now() + 30000;
    while (Date.now() < end) {
      const doSomethingHeavyInJavaScript = 1 + 2 + 3;
    }
    log('End heavy task', );
    resolve('Done');
  });
}

app.get('/non-block', (req, res) => {
  log('Non-blocked process called');
  doHeavyTask().then((result) => {
    res.send(result);
  });
});

@smitparaggua
Copy link

smitparaggua commented Sep 11, 2019

@minh-nguyen-hs, Promises doesn't run tasks in a separate thread. This is why event loop will still block. Node handles async tasks by letting go of event loop when waiting (usually while waiting for IO), then picking another task from the available tasks.

In your case, since doHeavyTask isn't actually waiting (it's keeping the CPU busy), it blocks the event loop.

@minh-nguyen-hs
Copy link

It makes sense, thank you @smitparaggua

@yeahga
Copy link

yeahga commented Nov 6, 2019

@minh-nguyen-hs,

function unblock() {
	return new Promise((resolve) => {
		setTimeout(resolve);
	});
}

function doHeavyTask() {
	console.log('Begin heavy task');
	return new Promise((resolve) => {
		const end = Date.now() + 30000;
		while (Date.now() < end) {
			await unblock();
		}
		log('End heavy task', );
		resolve('Done');
	});
}

app.get('/non-block', (req, res) => {
	console.log('Non-blocked process called');
	doHeavyTask().then((result) => {
		res.send(result);
	});
});

@samanyousefi
Copy link

@ghaiklor

I think your code is just a big mistake, please check the:
http://latentflip.com/loupe/

your call back function in your non-blocking API doesn't run in the backside of your code! when after 5000MS that setTimeout API finished that job and goes to callback queue, event loop catch that callback function and send that to the Stack for executing ! so that callback finally should run into the stack, and in this case, your code's show to non-blocking in stack not in event loop!

@Samjin
Copy link

Samjin commented Aug 25, 2021

Is there a way to tell blocking event from CPU flamechart? Even though a task can be promised, if it's a heavy task, it can still block next event loop right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment