JavaScript our dearly beloved programming is termed asynchronous and this is one of the things we love about it. JavaScript has an api for handling concurrent tasks, as is required of most high level languages. There is a neat way that JavaScript achieves this, which is quite different from what you'd be used to in Java or C. In this article we are going to explore this amazing part of JavaScript.
Concurrency
Often there is a need for a program to be able to execute certain commands out of the normal flow, without breaking other parts of the program. Much like you can see and listen at the same time, if we examine more closely you will find out these two phenomenal occur in parallel and at the same time, the collective result of both "programs" makes what's happening more clear to us. Similarly we as software engineers desire that our programs should behave in like manner.
It is very normal for a computer cpu to expose more than one core on which we can execute or run commands, JavaScript as a language was not designed to utilize more than one core, JavaScript code normally runs in a single thread manner where one statement is executed and then the next. This approach is logical, however there is often a need to "move" on to the next without waiting for the immediate to complete, going out of the normal flow as we pointed out earlier.
If we could not then our user would not get a good user experience, certain things like fetching data could cause glitches especially if your internet is not fast, thank God this isn't the case and we handle data fetching and other like actions asynchronously. We will now proceed to understanding how JavaScript implements its concurrency model.
Queue, Stack, Heap
Every JavaScript program is a self isolated process, it has its own queue a term we will look at shortly, stack another term we will look at, and its heap. The heap is a largely unstructured area of memory allocated to the objects in our code. Let's think of the heap as an area where messangers on horseback wait before they get to deliver their messages.
When it gets to the turn of a messenger they unmount and move to queue
. This area they are attended to in a first in first out manner, when each messenger dispatches their message, there is usually a reaction to that message, which in our case is a function call, for every message in the queue there is a function associated with it, that function is called when the message is processed out of the queue.
Each function call creates a stack frame that contains the statement and expression in the function, when that function returns a value or void, its frame is then popped out, the next function will begin executing, if we call a function inside another function a frame will be created for each. The frame for the nested function sits on top of the frame for the function that called it, when the nested function is done executing it will return and get popped of and the main function will continue executing or return and get popped off. The items in stack are treated in a last in first out format. The stack is a data structure that holds the frame for each function, we can deduce that this is a synchronous process, so how is concurrency achieved with the stack and the queue.
Event Loop
The event loop is simply a loop that iterates through the queue and processes any message if any is in the queue. Since we are in a JavaScript development environment messages could also be added to the queue as a result of events happening in the DOM. The event loop does not really care, its job is to process the messages in the queue. Its js interesting to remember that a stack frame which is in essence a function call can emit an event that adds a new message to the queue or it can directly add a message to the queue. So when the result of an expression might take long, there are APIs that allow us to add that result as a message when it is available to the queue, we go on processing other things without waiting. This is the basis of callback based code. This is also how setTimeout and setInterval adds messages asynchronously to the queue. When we write a setTimeout function a message is added to the queue after the specified delay in milisecs.
console.log("hello");
setTimeout(() => {
console.log("delayed")
}, 100)
Hello gets logged because it is immediately added to the queue and since there is no other task waiting to be added to the queue except of course the one from the setTimeout, which is added immediately, there's no 100ms delay guarantee that the message will be added to the queue, rather this is just a maximum delay if there are other messages in the queue waiting to be processed, however if this is not the case and there are no messages waiting in the queue, the task from the SetTimeout is added immediately ignoring the delay.
getSomeData(place, action)
// do something with place
let result = { data : place } // something
setTimeout(() => {
action(result)
}, 0)
}
getSomeData("london", console.log)
console.log("hey")
// call back based code
From the example above when the first function is executed a new stack frame is created, we create a variable and then use setTimeout to call the function passed in. as the second argument and give it the variable we created earlier when, if the first function has to take some time before completing the action would have to wait, but our code does not have to wait and it moves on to processing the next statement, when the result is ready action
is called with the result
passed in as an argument to the function. A new stack frame is created for it and the next message in the queue is processed if any.
The above process, the way the event loop as described above is synchronous, the event loop is usually expressed in terms of a while loop.
while(queue.waitForMessage()){
queue.processNextMessage()
}
When we pass in 0, as the delay this is does not always mean that the message will be added to the queue in zero seconds. The message will only be added to the queue when other messages in the queue has been processed. You should know that each stack frame must run to completion before another can be added on top of it. If you want to know more about asynchronous JavaScript i think you should read this article