Why is node.js asynchronous?
Asked Answered
F

3

59

Nobody has actually asked this (from all the 'suggestions' I'm getting and also from searching before I asked here).

So why is node.js asynchronous?

From what I have deduced after some research:

Languages like PHP and Python are scripting languages (I could be wrong about the actual languages that are scripting languages) whilst JavaScript isn't. (I suppose this derives from the fact that JS doesn't compile?)

Node.js runs on a single thread whilst scripting languages use multiple threads.

Asynchronous means stateless and that the connection is persistent whilst synchronous is the (almost) opposite.

Maybe the answer is found somewhere stated above, but I'm still not sure.

My second and last question related to this topic is this:

Could JavaScript be made into a synchronous language?

PS. I know some of you will ask "why would you want to make JS synchronous?" in your answers, but the truth is that I don't. I'm just asking these types of questions because I'm sure there are more people out there than just myself that have thought about such questions.

Fachini answered 12/7, 2013 at 4:4 Comment(1)
Thank you guys. All your answers were great and add a different value to the questions above. I won't vote any single answer as the best, as I believe you all your answers will matter to anyone else reading this question.Fachini
S
76

Node.js runs on a single thread whilst scripting languages use multiple threads.

Not technically. Node.js uses several threads, but only one execution thread. The background threads are for dealing with IO to make all of the asynchronous goodness work. Dealing with threads efficiently is a royal pain, so the next best option is to run in an event loop so code can run while background threads are blocked on IO.

Asynchronous means stateless and that the connection is persistent whilst synchronous is the (almost) opposite.

Not necessarily. You can preserve state in an asynchronous system pretty easily. For example, in Javascript, you can use bind() to bind a this to a function, thereby preserving state explicitly when the function returns:

function State() {
    // make sure that whenever doStuff is called it maintains its state
    this.doStuff = this.doStuff.bind(this);
}
State.prototype.doStuff = function () {
};

Asynchronous means not waiting for an operation to finish, but registering a listener instead. This happens all the time in other languages, notably anything that needs to accept input from the user. For example, in a Java GUI, you don't block waiting for the user to press a button, but you register a listener with the GUI.

My second and last question related to this topic is this:

Could JavaScript be made into a synchronous language?

Technically, all languages are synchronous, even Javascript. However, Javascript works a lot better in an asynchronous design because it was designed to be single threaded.

Basically there are two types of programs:

  • CPU bound- the only way to make it go faster is to get more CPU time
  • IO bound- spends a lot of time waiting for data, so a faster processor won't matter

Video games, number crunchers and compilers are CPU bound, whereas web servers and GUIs are generally IO bound. Javascript is relatively slow (because of how complex it is), so it wouldn't be able to compete in a CPU bound scenario (trust me, I've written my fair share of CPU-bound Javascript).

Instead of coding in terms of classes and objects, Javascript lends itself to coding in terms of simple functions that can be strung together. This works very well in asynchronous design, because algorithms can be written to process data incrementally as it comes in. IO (especially network IO) is very slow, so there's quite a bit of time between packets of data.

Example

Let's suppose you have 1000 live connections, each delivering a packet every millisecond, and processing each packet takes 1 microsecond (very reasonable). Let's also assume each connection sends 5 packets.

In a single-threaded, synchronous application, each connection will be handled in series. The total time taken is (5*1 + 5*.001) * 1000 milliseconds, or ~5005 milliseconds.

In a single-threaded, asynchronous application, each connection will be handled in parallel. Since every packet takes 1 millisecond, and processing each packet takes .001 milliseconds, we can process every connection's packet between packets, so our formula becomes: 1000*.001 + 5*1 milliseconds, or ~6 milliseconds.

The traditional solution to this problem was to create more threads. This solved the IO problem, but then when the number of connections rose, so did the memory usage (threads cost lots of memory) and CPU usage (multiplexing 100 threads onto 1 core is harder than 1 thread on 1 core).

However, there are downsides. If your web application happens to also need to do some heavy number crunching, you're SOL because while you're crunching numbers, connections need to wait. Threading solves this because the OS can swap out your CPU-intensive task when data is ready for a thread waiting on IO. Also, node.js is bound to a single core, so you can't take advantage of your multi-core processor unless you spin up multiple instances and proxy requests.

Stela answered 12/7, 2013 at 5:43 Comment(1)
This is really awesome, also the part of CPU bound - can you please further clarify as to why JS is not good for CPU Bounded operations - what are those JS complexities and how one can come around itCummings
I
36

Javascript does not compile into anything. It's "evaluated" at runtime, just like PHP & Ruby. Therefore it is a scripting language just like PHP/Ruby. (it's official name is actually ECMAScript).

The 'model' that Node adheres to is a bit different than PHP/Ruby. Node.js uses an 'event loop' (the single thread) that has the one goal of taking network requests and handling them very quickly, and if for any reason it encounters an operation that takes a while (API request, database query -- basically anything involving I.O. (input/output)) it passes that off to a background 'worker' thread and goes off to do something else while the worker thread waits for the long task to complete. When that happens the main 'event loop' will take the results and continue deal with them.

PHP/Ruby following a threading model. Essentially, for every incoming network request, the application server spins up an isloated thread or process to handle the request. This does not scale tremendously well and Node's approach is cited as one of its core strengths compared to this model.

Asynchronous means stateless and that the connection is persistent whilst synchronous is the (almost) opposite.

No. Synchronous instructions are completed in a natural order, from first to last. Asynchronous instructions mean that if a step in the flow of a program takes a relatively long time, the program will continue executing operations and simply return to this operation when complete.

Could JavaScript be made into a synchronous language?

Certain operations in JavaScript are synchronous. Others are asynchronous. For example:


Blocking operations:

for(var k = 0; k < 1; k = k - 1;){
  alert('this will quickly get annoying and the loop will block execution')
alert('this is blocked and will never happen because the above loop is infinite');

Asynchronous:

jQuery.get('/foo', function (result) { alert('This will occur 2nd, asynchronously'); });
alert('This will occur 1st. The above operation was skipped over and execution continued until the above operation completes.');
Intoxicating answered 12/7, 2013 at 4:35 Comment(7)
Javascript does not compile into anything. is wrong. Node.js uses V8 which includes a JIT compiler that compiles Javascript to machine code. For PHP there are plenty solutions that can compile the code. Ruby does not evaluate the sourcecode but runs on a abstract syntax tree. -> The language itself does not imply if it is interpreted or compiled but the concrete implementation the question is about is not interpreted in a classical sense.Crossstitch
@Fresheyeball "V8 compiles JavaScript source code directly into machine code when it is first executed. There are no intermediate byte codes, no interpreter." See the v8 design docs -> Dynamic Machine Code GenerationCrossstitch
@Crossstitch JS does not compile any more than PHP or Python. V8 is an awesome runtime, but you give it plain text script, not a compiled binary.Nightjar
@BaileyS It behaves like an interpreter, but it operated in many ways like a compiler would and is usually called JIT compiler. It's a bit of a gray area, but I think calling it 'compiling' is not unjustified.Cupel
@Cupel My point was that any JIT compiled language has the same property, so they are either all still scripting languages, or they aren't. Considering that a JIT compiler could be written for pretty much any language, would that mean scripting languages no longer exist? Or is there something else to it? This is all horribly semantic, but my real point is that the internal operation of V8 does not put JS in a different class than PHP and Ruby.Nightjar
@BaileyS Its better to think about compiled and interpreted implementations, since languages can have several. If someone writes a very fast compiler for PHP somehow, the language is still the same. So I guess I agree that adding a new compiler doesn't re-categorize a language, but not because JIT compilers aren't real compilers.Cupel
Fair enough but JIT compiling is middle ground of compiled languages vs. scripting languages. JavaScript is a scripting language; hence its name.Paten
A
25

Could JavaScript be made into a synchronous language?

Javascript is not an "asynchronous language"; rather, node.js has a lot of asynchronous APIs. Asynchronous-ness is a property of the API and not the language. The ease with which functions can be created and passed around in javascript makes it convenient to pass callback functions, which is one way to handle control flow in an asynchronous API, but there's nothing inherently asynchronous about javascript. Javascript can easily support synchronous APIs.

Why is node.js asynchronous?

Node.js favors asynchronous APIs because it is single-threaded. This allows it to efficiently manage its own resources, but requires that long-running operations be non-blocking, and asynchronous APIs are a way to allow for control of flow with lots of non-blocking operations.

Alarise answered 12/7, 2013 at 5:25 Comment(1)
Old thread but Yes JavaScript by design is asynchronous. This why you can have multiple JS controls on a web page-- each has a listener waiting in the backround to call a function when activated. The system goes through all the listeners and checks for an event that tells it to activate its function. Why you generally dont want "blocking" code, such as an alert(). Because everything else stops waiting for the "blocking" code to complete. Including listeners. Basically, "non-blocking" code allows for things to go through all the listeners and multitask. It switches between tasks quicjlyCharmian

© 2022 - 2024 — McMap. All rights reserved.