Javascript concurrency in the browser #1

Javascript concurrency in the browser #1

JavaScript as a language was design as an embedded scripting language. The programs that run in JS are not stand-alone applications, but merely a script in the context of a larger application.

The main example of this is, of course, the browser. A browser can run multiple tabs simultaneously listening to many events in parallel and responding accordingly. In a perfect world, no mater the rich UI experience provided by the website, the browser will stay responsive all the time.

Before we begin a serious discussion about concurrency in JavaScript, we must understand the following: JavaScript is a single-threaded language. From the language point of view, all code is executed on one main thread. The context in which the code is executed can provided ways various operations (http request, timers, animations) to be executed in parallel without blocking the main thread. This is vital for a good user experience. In this article we will analyze how JS run in the browser and how this operations are possible.


Prerequisites

You should be familiar with the basic concepts of execution context and scope before diving into this topic. I recommend you to read Javascript – Execution context and scope before this.


Javascript runtime

We know so far that at runtime, JavaScript can do only one thing at the time (on one thread). However, the browser is more than the JS main execution thread. Browser enhance the power of JS by providing a collection of Web APIs. They can handle different types of operations – DOM manipulation, ajax (XmlHTTPRequest), setTimeout, etc -. They behave exactly like threads, the JS access them and resumes execution on the main thread. When a result comes back from the Web API, it will be handled in the main thread.  In the meantime, the main thread run with no hick-ups.

Let’s see a visualization of how JS run in the browser:

Screen Shot 2017-10-01 at 5.17.35 PM.png

The main actors involved in running JS in the browser are:

The stack 

The execution context of Javascript at runtime is represented as a stack.

At the bottom of the stack is always the global context. The global context will be destroyed only when the program is ended.

Every time a new function is called, a new context is created and add it on top of the stack. It will remain there until the execution of that function is ended. At any point in time, in stack will be the functions which are called and haven’t finish execution yet. (see more here).

The heap

The heap is the place where all the variables kept in memory are stored. When a variable is declared, a new address from the heap is allocated with it’s value. When the variable looses it’s reference, the garbage collector will remove it from the heap.

Web APIs

Web APIs are a collection of tools provided by the browser to enhance the power of Javascript. Using them you can achieve true concurrency in Javascript. The operation is executed on a different thread in parallel with the main thread. When the operation is completed, a callback is added in the queue.

The queue

The queue is the place where all the pending operations are waiting to be executed. For example, when an event occurs on the UI, or a result from a http request has arrived, the callback is put on the queue and waits for its turn on the execution thread.

Event loop

The event loop has the role to observe the stack and the queue. Whenever the stack is empty (except the execution context), it means that, at that point there is no operation performed in the browser. At that moment, the event loop takes the first operation from the queue and add it to the stack.

Remember:

  • Javascript is a single-threaded language – the code is executed on one main thread at runtime
  • Concurrency in the browser is achieved by using Web APIs for async operations (like http request or timeout) – they perform the operation on a different thread.
  • Whenever an event happens in the browser or a web api finishes the execution, the callback for handling the result is added in the queue. When the execution stack is free, the event loop will add the next operation from the queue in the stack in order to be executed

The mystery behind setTimeout({}, 0)

You may have encountered in the past a timeout set to 0 which may seem a bit odd.

Now that we know how JS works in the browser, we can give the explication for this: A timeout 0 is used when you want to defer the execution of a code.

The callback is put in the back of the queue and it will be executed only if the stack is free and all other callbacks waiting in the queue are resolved.

This is a commonly used hack in angular for making sure that the code is executed in the next digest cycle.

Let’s assume a board game played between the user and the computer in JavaScript.

The computer move is calculated using a recursive function which calculates all the possible moves. The algorithm is very time consuming and it would definitely block the main thread for few seconds. One solution for this is to defer each function call using setTimeout 0. This way, if other events occur in the browser, they could be handle and the algorithm will continue after it.

function nextMove(step) { 
    // calculate the value for nextStep 
    
    setTimeout(nextMove(nextStep), 0}; 
}

This way, every call of nextMove() function is added in the queue. If other callbacks are added meantime, they will be handle between calls. If I would use simply nextMove(nextStep) instead setTimeout(nextMove(nextStep)) the runtime thread would have been blocked until the function has exited.

Final words

Thank you for your time!

Next week we will continue this series with Javascript concurrency in the browser #2 which will include more about:

  • best practices on concurrency 
  • how to avoid blocking event queue in the browser on I/O
  • dropped errors and error handling in web APIs
  • promises and async/await statements in JS

Please subscribe to keep in touch!

One thought on “Javascript concurrency in the browser #1

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s