How does JavaScript's Single Threaded Model handle time consuming tasks?

1.2k views Asked by At

This question is regarding the sinlge threaded model of JavaScript. I understand that javascript is non-block in nature cause of its ability to add a callbacks to the async event queue. But if the callback function does infact take a long time to complete, won't JavaScript then be blocking everything else during that time as it is single threaded? How does nodejs handle such a problem? And is this an unavoidable problem for developers on the front end? I'm asking this question cause I have read that its generally good practice to keep function tasks as small as possible. Is it really because long tasks in javascript will actually block other tasks?

2

There are 2 answers

0
Burdock On

Your question is a very large one, so I am just going to focus on one part.

if the callback function does infact take a long time to complete, won't JavaScript then be blocking everything else during that time as it is single threaded? (...) Is it really because long tasks in javascript will actually block other tasks?

Non-blocking is a beautiful thing XD

The best practices include:

  • Braking every function down into its minimum functional form.
  • Keep CallBacks asynchronies, THIS is an excellent post on the use of CallBacks
  • Avoid stacking operations, (Like nested Loops)
  • Use setTimeout() to brake up potentially blocking code
  • And many other things, Node.JS is the gold standard of none blocking so its worth a look.

--

--

setTimeout() is one of the most important functions in no-blocking code

So lets say you make a clock function that looks like this:

function setTime() {
    var date=new Date();
    time = date.getTime()
    document.getElementById('id').innerHTML = time;

}
while(true){setTime();}

Its quite problematic, because this code will happily loop its self until the end of time. No other function will ever be called. You want to brake up the operation so other things can run.

function startTime() {
    var date=new Date();
    time = date.getTime()
    document.getElementById('id').innerHTML = time;
    setTimeout(startTime(),1000);
}

'setTimeout();' brakes up the loop and executes it every 1-ish seconds. An infinite loop is a bit of an extreme example. The point is 'setTimeout();' is great at braking up large operation chains into smaller ones, making everything more manageable.

0
Brad On

But if the callback function does infact take a long time to complete, won't JavaScript then be blocking everything else during that time as it is single threaded?

Yes.

How does nodejs handle such a problem?

Node.js handles nothing. How you handle concurrency is up to you and your application. Now, Node.js does have a few tools available to you. The first thing you have to understand is that Node.js is basically V8 (JavaScript engine) with a lightweight library split between JavaScript and native code bolted on. While your JavaScript code is single-threaded by nature, the native code can and does create threads to handle your work.

For example, when you ask Node.js to load a file from disk, your request is passed off to native code where a thread pool is used, and your data is loaded from disk. Once your request is made, your JavaScript code continues on. This is the meaning of "non-blocking" in the context of Node.js. Once that file on disk is loaded, the native code passes it off to the Node.js JavaScript library, which then executes your callback with the appropriate parameters. Your code continued to run while the background work was going on, but when your callback is dealing with that data, other JavaScript code is indeed blocked from running.

This architecture allows you to get much of the benefit of multithreaded code without having to actually write any multithreaded code, keeping your application straightforward.

I'm asking this question cause I have read that its generally good practice to keep function tasks as small as possible. Is it really because long tasks in javascript will actually block other tasks?

My philosophy is always to use what you need. It's true that if a request comes in to your application and you have a lot of JavaScript processing of data that is blocking, other requests will not be processed during this time. Remember though that if you are doing this sort of work, you are likely CPU bound anyway and doing double the work will cause both requests to take longer.

In practice, the majority of web applications are IO bound. They shuffle data from a database, reformat it, and send it out over the network. The part where they handle data is actually not all that time consuming when compared to the amount of time the application is simply waiting to hear back from the upstream data source. It is in these applications where Node.js really shines.

Finally, remember that you can always spawn child processes to better distribute the load. If your application is that rare application where you do 99% of your work load in CPU-bound JavaScript and you have a box with many CPUs and/or cores, split the load across several processes.