Exploring the Event Loop

Introduction

Ikram Saedi introduces the talk "It Feels Parallel But It's Actually Sequential: Exploring the Event Loop," which aims to explain the concept of parallelism in JavaScript and answer whether JavaScript is truly parallel.

The Illusion of Parallelism in JavaScript

Ikram discusses why JavaScript feels parallel, using examples like website interactions, animations, and background processes happening seemingly simultaneously. She contrasts this with the frustrating experience of a non-parallel system where users constantly face loading screens.

Parallelism vs. Concurrency

Ikram uses the analogy of cooking with a friend to illustrate the difference between parallelism (two chefs managing two pots simultaneously) and concurrency (one chef switching between managing two pots). She highlights how concurrency uses fewer resources while achieving similar results.

Parallelism in Computing

Moving from the cooking analogy to computing, Ikram explains that true parallelism involves running processes on separate CPU cores at the same time. She points out that computers can handle many more processes than the number of cores, hinting at the role of concurrency.

Threads: Streams of Work

Ikram introduces the concept of threads as lightweight, non-isolated processes that share resources within a process. She contrasts this with processes that have their own dedicated memory space. She promises this concept will be relevant later in the talk.

Threads vs. Processes in Chrome

Ikram uses the example of Chrome's tab isolation to further differentiate threads and processes. She explains how isolating tabs as separate processes prevents one unresponsive tab from crashing the entire browser window, unlike threads which could bring down the whole window.

JavaScript: A Single-Threaded Language

Ikram states that JavaScript is single-threaded, meaning it has only one stream of work. This implies that, in theory, each action in JavaScript should block the next, leading to a poor user experience.

Non-Blocking JavaScript

Ikram demonstrates how JavaScript achieves a non-blocking nature despite being single-threaded. She uses the example of uploading a video on Twitter while still being able to interact with the user interface, highlighting the role of concurrency.

The Event Loop: Managing Asynchronous Operations

Ikram introduces the event loop as the mechanism behind JavaScript's non-blocking behavior. She explains that the event loop manages the flow of function calls between the call stack and the event queue.

Understanding the Call Stack

Ikram explains the call stack as a LIFO (Last-In, First-Out) data structure, analogous to a stack of books. She describes how function calls are pushed onto the stack and popped off when they return, using a code example to illustrate the process.

The Event Queue and Web APIs

Ikram describes the event queue as a FIFO (First-In, First-Out) queue where events from Web APIs are placed. She explains that Web APIs are built-in browser functionalities like DOM manipulation, console logging, and network requests.

How the Event Loop Works: A Tweet Example

Ikram revisits the Twitter tweet example to illustrate the interaction between the call stack, event queue, and Web APIs. She walks through the steps of uploading a video, typing a tweet, and adding an emoji, showing how the event loop prevents blocking.

The Event Loop's Simple Logic

Ikram summarizes the event loop's function as continuously checking the call stack and pushing the first function from the event queue onto the stack when it's empty, highlighting its continuous and iterative nature.

Interacting with the Event Loop: Asynchronous Operations

Ikram emphasizes that asynchronous operations like setTimeout, Promises, and async/await are key to understanding the event loop's impact. These operations demonstrate how JavaScript can handle tasks without blocking the main thread.

Illustrating the Event Loop: A Cat Animation

Ikram presents a visual simulation of the event loop using a cat animation, demonstrating how the event loop processes tasks, interacts with Web APIs, and ensures smooth execution of asynchronous operations.

Challenges and Solutions in Animation Implementation

Ikram discusses challenges she encountered while creating the animation, specifically with queuing animations correctly. She explains how she used Promises and async/await to ensure animations happened sequentially, creating a smoother visual flow.

Alternative Approaches to Concurrency: Multithreading

Ikram acknowledges that the event loop is not the only way to achieve concurrency. She introduces multithreading, where multiple threads within a process run in parallel, as an alternative approach used in other programming languages.

Comparing Multithreading and the Event Loop

Ikram compares multithreading and the event loop, highlighting their respective strengths and weaknesses. She notes that both are suitable for I/O-bound tasks (waiting for external input/output), but multithreading can be advantageous for CPU-intensive operations.

Debunking the Myth of Parallelism in Multithreading

Ikram clarifies that multithreading, while appearing parallel from a programmer's perspective, isn't truly parallel as it doesn't necessarily use multiple CPU cores. The illusion of parallelism comes from the rapid switching between threads managed by the computer.

JavaScript's True Nature: Sequential Execution

Ikram concludes by affirming that JavaScript, despite its asynchronous capabilities, is fundamentally sequential. She reiterates that tasks happen one after the other, though the event loop and asynchronous operations create the illusion of parallelism.

Closing and Contact Information

Ikram shares her contact information, including her Twitter handle, GitHub profile, and a link to the event loop simulation. She thanks the audience for their time and attention.

Okay, cool.

Thank you so much for introducing me.

This is the talk of It Feels Parallel But It's Actually Sequential Exploring the Event Loop by me.

This talk will delve into what parallelism really means and answer the question as to whether or not JavaScript is actually parallel.

This talk requires some basic JavaScript knowledge but whether or not you are experienced or new to programming, I hope this talk will be useful to you.

Let's get started.

Cool.

Why does JavaScript feel parallel?

As a user interacting with a website, there's just so much happening all at once.

You can be mousing over a bunch of different things, clicking on things, copying and pasting, typing in a bunch of stuff.

The possibilities are endless.

As you're doing all of this, the components on your page are constantly re rendering, they're animating, there may be a bunch of fetch requests happening in the background.

And in the meanwhile, you're not necessarily just continually waiting for a loading screen.

When would it not feel parallel?

If you are constantly watching the spinning wheel of death, as I'm sure many of you are familiar with, this is a really, sucky experience.

This is when things would not feel like they ever would.

It would not feel like a bunch of things are happening simultaneously, you're just waiting and waiting endlessly.

What does parallelism actually mean?

I like to think about it as a cooking night with a friend.

You have two people managing and cooking each pot of food.

I really like cooking like a rice and a curry at the same time.

If I have a friend over, let's say they're taking care of the rice pot and I'm taking care of the curry pot.

Here we have a diagram.

For each pot, we have a Red rectangle and we also have beige rectangles.

The red rectangles are just the amount of time that you are like actively spending on cooking each pot and the beige is just where you're like standing back and not actually doing anything.

For example, my friend could be washing and boiling the rice, doing nothing, simmering the rice, doing nothing, and then they'll turn the rice off and your rice is done.

Me, on the other hand, I have a lot more work to do.

I have to put in my onions and garlic, I can chill for a little bit, but then I've got to put in my spices, my tomatoes, my other vegetables, and I'll keep on going until my dish is done.

But a way, more likely, situation for me is concurrency.

So instead of me having a friend over, it'll just be me cooking dinner just for myself.

So instead, I will be managing both the rice pot and the curry pot.

Cool.

Instead it will look something more like this.

I first am actively managing the rice pot.

So I've got, I'm like washing and boiling my rice.

Now I don't need to do anything as it boils, I'm handing off that task back to the burner.

Then I'm switching back to my, I'm switching over to my curry pot.

And now I can like, saute my onions and my garlic.

But hey, the burner has let me know, has let me know that the rice is finished boiling, I can turn it down, I can turn it down to a simmer.

I can switch back to my curry, I can do a bunch of stuff, I can add in my spices, tomatoes and vegetables, then go back to my rice, et cetera, et cetera.

I'm constantly switching back, And fourth, and in both scenarios you still end up with a rice and a curry, except with concurrency you're using less resources and with parallelism you're using more.

What is parallelism in computing?

So away from the chefs.

So when two processes, it's when two processes are running on two separate cores in the CPU simultaneously.

So at exactly the same time, eight processes can be run on an eight core MacBook Air.

So you can think about each core like a chef, and each process like a pot.

However, you can do many, more things than just eight things at once on an eight core MacBook Air.

If you're like me, I can have a hundred different tabs open all at once.

It's way, way, more than eight.

So this is just a screenshot of Activity Monitor, on the MacBook, where you can see all of the different processes that are running.

Right now, and clearly, we have 409.

That is a lot more than 8.

So how is this actually working?

So your computer is actually switching between processes like millions and millions of times a second.

So at exactly, at the exact nanosecond or millisecond or whatever, you will have actually 8 processes running, but within the span of a second, your computer may have switched between 409.

And then you may have also noticed something sitting right above it, which is threads.

So what is that?

Basically, you can have many, threads associated with a process.

So as you can see, we have 3, 289 threads here.

And they're basically a stream of work on a process.

They're essentially, In a process, they are essentially a process, but like a light version of one.

They don't get their own space and memory, and because they're not isolated, threads can interfere with each other.

I promise this will be relevant later in the talk.

This is not a tangent.

Thread versus processes, Chrome is famous for tab isolation.

It implements this by creating a process for each tab.

If one tab becomes fully unresponsive, then the entire Chrome window will not necessarily have to fully crash.

But, with threads, it would probably take down your whole window, which would suck.

So how does JavaScript fit into all of this?

It is a single threaded language, using only a single process, so there is only one stream of work, and in theory, every action would have to block the next one.

And what would that mean for us?

Here you can see my really cute cat, Loaf, who I'm going to be referring to constantly throughout this talk.

He is the most important piece of information that you can get out of this talk, so if you get anything, please remember his name.

But let's say you want to go post a tweet onto Twitter to talk about your cat, and you want to upload a cute video of him.

If JavaScript was a blocking language and you first decided to upload a video of your cat and then you were like, oh, I actually want to write some text, you would have to wait for the full 20 seconds or however long it takes for your video to upload before you're able to interact with the rest of the page.

So it looks something like this.

These are arbitrary, arbitrary measurements, but, for example, it could take, 20 seconds for the, post request to the Twitter upload's endpoint, to, give you a successful response.

And then only after that are you able to do a bunch of typing and add in some cute emojis, which would really suck.

For example, you've pressed the upload button, and now you're just watching the spinning wheel of death for 20 seconds, you'd be counting down, 1 1000, 2 1000, 3 1000, and it's taking forever, right?

I'm not gonna wait.

But then, now you're finally able to type in your stuff, and now you're finally able to add in your cute little cat emoji.

But, JavaScript is non blocking, so you can upload your cute cat video to the world, but then also still interact with the rest of Twitter's UI in the meantime.

Here I'm able to upload my cute cat video, and I only really have to wait, actually like a millisecond or so, and then I'm able to type in my hello cutest cat in the world, I'm able to add in my emoji, and all is well.

It is a concurrent single threaded language and it can multitask just like me cooking.

Why does it work this way?

The reason why it works this way is because of the event loop.

And what is the event loop?

The event loop basically manages like the flow of function calls between primarily the call stack and the event queue.

So let's take a look at what each of these data structures actually mean.

And let's start off with the call stack.

What is the call stack?

The call stack is a last in, first out data structure.

I personally find it really helpful to think about it like a stack of books.

The last book you put on the top of your book stack is the first one you can pick up without causing the entire pile to fall apart.

And the same applies to functions in JavaScript.

But instead of books, we have frames, and frames correspond with a function that has been called, and a function is pushed onto the stack when it has been called, and is removed or popped off the stack when it returns.

So to go through just a really simple example, we have a function called first.

First just returns a, double of a number, so for example, one.

Then, we, in order to double it, it will have to push the double frame onto the call stack, and then double will be calling multiply, which is another function, which will also now, wrong function name, but that's okay, pretend the top one is multiply, and, yeah, that will also need to be pushed onto the call stack.

Now we've successfully doubled our number, multiply now has returned, it's given you two, then it will be popped off the call stack.

Then double has returned as well, it has popped off the call stack, and first has now returned as well, and your call stack is now empty and clear.

Now, what is the event queue?

The event queue is just like a queue of people, it's diversity and first served.

And the, events get pushed to the event queue from a web API of some sort.

And then what is the web API?

This is just a broad umbrella term for a bunch of different web APIs that come embedded in JavaScript's browser engine.

So common examples include the HTML DOM API, the console API, the URL API, the fetch API, I didn't realize that all of these were kind of APIs that were actually sitting in your browser.

I never really thought about them until I researched this.

So I thought that was really interesting.

And back to what the event loop actually is.

Let's run through an example.

Going back to my example of creating a tweet about my cute cat, Loaf.

Let's say we have a function called createLoafTweet.

It will post and upload to Twitter, then it will, once that upload has finished uploading, it will console.log the loaf video has been uploaded, then we can type in our tweet, and then we can also add our emoji.

So what would this look like?

First we call the createLoafTweet function, this will be pushed onto the call stack.

Then we call the postTwitterUpload function, which is then pushed onto the call stack.

This will then get shifted off for the fetch API to handle, because it's making a fetch request to the twitterUploadsAPI endpoint, and it's ticking over in the meantime, but it's no longer on the stack.

It's been popped off the call stack.

Now we can type in our tweet, which is the next function call, and that is happening whilst the upload has been uploading in the Twitter API.

Then that's been removed off the call stack.

Then we add in our cute little cat emoji at the end.

And then, we've pushed that, popped that off the call stack, and then now, the entire createLoafTweet function has been popped off the call stack.

However, our Twitter upload is still sitting in the API.

And we can wait around for 20 seconds, but I'm not going to do that.

Let's pretend it's finished executing, and then it will, so the little arrow function here is what I'm trying to refer to when I'm using the dot then in the Fetch API.

All right.

This will then get pushed onto the event queue, and then the event loop is like, hey, there's nothing in the call stack, so let's push in our then, callback into the call stack, and then we can use our console log for loafVideoUploaded, and then we're done.

We've pushed off the loaf video has been uploaded, and then we've pushed off the then call back as well.

What is the event loop actually doing?

It's actually very, simple.

All it's really doing is constantly checking that the call stack is empty.

If it is, it will push the first function call from the event queue into the call stack.

How you interact with it.

Anything asynchronous, and I feel like that is when you start really tangibly interacting with the event loop.

Set timeouts, promises, async awaits, are all things that easily display the true nature of the event loop.

Cute cat intermission.

I have a cute little simulation, of the event loop using some really cute cats.

Let's see if I can get this guy up, please.

Cool.

Okay.

We have our cute little event loop.

Here's my little cat in the corner.

His name is Loaf.

He is the event loaf now.

We're going to click the center button.

This will order us a loaf of bread.

Click this guy, and he will pick up our loaf order and chuck it onto the call stack.

Now we'll need to prepare it and send it off to the kitchen.

And our lovely Chef Web API.

We'll be cooking it in the meantime.

Now, he's finished, we've finished preparing, and we've finished the order loaf, but we haven't fully served the loaf yet.

Our Chef API has delivered it to the event queue, And then, eventually, our little server event loaf will pick it up from the event queue, and then we'll drop it into the call stack for it to be executed, and then ta da!

Our loaf has been served.

And that is the event of the simulation.

Thank you!

[applause] Okay.

I ran into some issues when actually creating this animation.

I did a bit of an oopsies when I first made it.

I was not properly queuing my animations one after the other, and I totally failed at it.

If we take a look, close look at this function, we have just a function called move.

It is like a kind of contrived example from my actual code that I used.

So I have some keyframes just telling my loaf where to go, and just telling him to transform and translate to different coordinates on, the page.

Then I've got some animation options.

All they're really doing is just saying, hey, this animation lasts for three seconds.

And let's zoom in on these two.

Here in my first one, I'm saying, hey, can you please move to the center button to pick up the order loaf.

And then after that, I want him to move to the call stack to drop it in.

However, the second animation does not wait for the first animation to finish.

And it looks a little bit funky.

As we can see, I've clicked my autoloaf and oh, he didn't magically move over to the autoloaf.

He just appeared and like just teleported there and looks really, weird.

So if you play that again, just magically appears in the center of the screen.

No smooth transition at all.

So the way in which I fix this, is adding in the dot finished at the end of my cat dot animate block.

So the finished will return a promise.

And now I'm saying hey.

Only after this first animation has finished, will we then go on to the next animation.

And we're essentially like saying, hey, JavaScript, please wait for this first animation to finish.

A nice cleaner way to do it is using async await as well.

Same thing, but just cleaner syntax.

Hey, please wait for the first animation to finish.

Then please wait again for our second animation to finish.

And when using Promises, every line of code that is awaited or then is put into the event queue rather than being immediately executed in the call stack, which is great.

You can actually ensure that your animations are queued one after the other.

How do other languages implement concurrent multitasking?

Because JavaScript is not the only language in the world.

There are so many others that implement , that have to implement something similar.

Multithreading is an alternative, right?

This is when, within a process, multiple threads are being executed in parallel.

For example, something someone would do would be to use one thread to handle incoming requests, another thread to handle a bunch of CPU intensive work.

And both multi threading and the event loop are good for, I O work, which is basically when you're waiting for an input and, sorry, waiting for, the result of an API request or something, and then switching over.

And handling things.

Okay, cool.

When is multithreading better than the event loop?

Imagine you've implemented a search field where on every key press you're iterating over a large amount of data to find the search result.

This leads to a very laggy experience when typing because the function invocations stay primarily in the call stack and they're not handed off to a web API or anything like that.

And you can end up with a really laggy typing experience.

Something like this, where you just have things just jumping on the page, it's not smooth, it's not, real time typing.

However, in theory, multi threading, the CPU processing can happen without slowing down the UI, and you're able to just type freely.

However, the event loop does have a really big leg up over multi threading.

It's way simpler and it's a lot more predictable, it's a lot easier to debug, you will not necessarily have threads that are randomly switching in the middle of executing a function, and you know exactly how your functions are going to be executed.

Is multi threading parallel?

Not in the true sense.

I actually did think it was parallel when I first looked into it.

But it is not because it does not require multiple CPU cores.

To you as a programmer it may as well be the computer kind of handles the switching between different threads for you at the CPU level.

But it is not truly parallel.

Is JavaScript sequential?

Yes.

No two things are actually happening at exactly the same time in JavaScript.

It is always one after the other and this is far simpler than true parallelism as well as multi threading.

As I was introduced earlier, I'm a software engineer at an edtech company called Stile Education.

I have my Twitter handle up here and my GitHub handle, as well as a link to my event load simulation, which is also just on my GitHub.

Everything is just my first and last name.

So I'm very easy to find and yeah, thank you so much for listening.

EXPLORING THE EVENT LOOP

Ikram Saedi

Software Engineer
Stile Education

Exploring the Event Loop

It feels parallel, but is actually sequential: exploring the Event Loop.

Ikram Saedi

Paper plane drawing at bottom right and abstract squiggle at bottom left.

Why does JavaScript feel parallel?

There's so much happening all at once! Surely it is all being handled in parallel?

Illustration of a laptop amongst various technical devices and icons, signifying complex interactions.

When would it not feel parallel?

Constant spinning wheel of death

A browser window displays a spinning rainbow wheel

What is Para

A browser window with the text "What is Para" inside it, accompanied by a heart icon on the left.

Parallelism

An illustration shows two large cooking pots labeled 'Rice pot' and 'Curry pot', each with a small character holding a whisk beside them.

Exploring the Event Loop

Parallelism

Illustrations of a person in a chef outfit, a pot of rice, and a pot of curry alongside timelines marked with cooking steps.

Concurrency

Two large cooking pots, labeled "Rice pot" and "Curry pot", with a small chef character pointing at them.

Concurrency

Illustration of a person cooking with two pathways, one for cooking rice and one for curry, with each pathway showing different steps in the process. The rice steps include washing and boiling, simmering, and turning off. The curry steps include sauteing onions and garlic, adding spices and vegetables, and continuing to cook.

End Result

A bowl of curry with rice, garnished with herbs, and placed on a wooden surface with greens around.

What is parallelism in computing?

  • When two processes are running on two separate cores in the CPU simultaneously
  • At exactly the same time, 8 processes can be run on an 8 core MacBook Air
Illustration showing two cores, each running a separate process, demonstrating parallelism in computing.

What is parallelism in computing?

Your computer actually switches between processes millions of times a second

Activity Monitor graph displaying CPU Load statistics, including System, User, Idle percentages, and the number of Threads and Processes.

What is a thread?

Can have many threads associated with a single process

Illustration showing CPU load statistics with labels "System," "User," "Idle" and a graph of CPU load over time. The illustration shows 3,289 threads and 409 processes.

What is a thread?

  • It is a stream of work on a process
  • They are essentially a process, but a lite version of one -- they don’t get their own space in memory
  • Because they are not isolated, threads can interfere with each other

How does JavaScript fit into all this?

  • It's a single threaded language
  • Only one stream of work, in theory every action would have to block the next one

What would that mean for us?

  • Uploading a cute cat video to Twitter would mean you would have to watch a loading spinner for ages
  • Cannot interact with the rest of the page
A screenshot of a tweet displaying a video upload interface with a video of a sleeping cat and an upload progress bar indicating 43%.

What would that mean for us?

  • POST request to Twitter uploads (20s)
  • tweet editor keydown handler (2ms)
  • emoji button onClick (2ms)
A browser window displaying a video of a cat on the left.

But JavaScript is non blocking

  • POST request to Twitter uploads (1s)
  • emoji button onClick (2ms)
  • tweet editor keydown handler (1ms)
  • Video upload response from Twitter (1s)

But JavaScript is non blocking

  • It is a concurrent single threaded language
  • It can multitask just like me cooking!

Exploring the Event Loop

Why does it work this way?

The event loop!

An illustration of a circular loop with arrows indicating a continuous cycle.

What is the event loop?

Diagram showing the event loop process with three blocks representing Call Stack, Web API, and Event Queue, including arrows indicating the flow between them.

What is the call stack?

Call stack

Last in, first out
Illustration of three colored books stacked next to three stacked red rectangular blocks

What is the call stack?

Call stack

  • A stack of frames
  • A frame corresponds with a function that has been called
  • A function is pushed onto the stack when it has been called
  • And is removed (popped off) the stack when it returns

An illustration of a Call stack with three frames, highlighted, and labeled as "Frame".

What is the call stack?

Call stack

first

Call first()

function first(x) {
    return double(x)
}
first(1)

A diagram of a browser window displaying a call stack with the function 'first' being called, and a code snippet on the right side showing the function definition and call.

What is the call stack?

Call stack

  • double
  • first
first() calls double()
A graphical interface depicting the hierarchy of the call stack with two boxes labeled "double" and "first", and a code snippet showing the function 'first(x)' which returns 'double(x)'.

What is the call stack?

Call stack

  • increment
  • double
  • first

double() calls multiply()


function first(x) {
    return double(x)
}

first(1)

function double(x) {
    return multiply(x, 2)
}

function multiply(a, b) {
    return a * b
}
Diagram illustrating the call stack with functions increment, double, and first. Includes code snippet showing the functions first, double, and multiply, with their respective behaviors.

What is the call stack?

Call stack

first
double() returns and is popped off
Diagram of a call stack with a single frame labeled "first". Also includes a code snippet: function first(x) { return double(x) } first(1).

What is the call stack?

Call stack

first() returns and is popped off

A label "Call stack" and an empty square representing the call stack. The window has a title bar with navigation buttons, a search field labeled "Exploring the Event Loop," and a tab label "about:blank".

What is the web API?

Web API

This is just a broad umbrella term for an arbitrary web API that comes embedded in JavaScript's browser engine

Common examples include:

  • HTML DOM API
  • Console API
  • URL API
  • Fetch API

A diagram depicting the structure of a Web API.

What is the event loop?

Call stack
Web API
Event Loop
Event Queue

Diagram illustrating the event loop with elements like the call stack, web API, event loop, and event queue connected by arrows.

Example

function createLoafTweet() { 
    postTwitterUpload().then(() => { 
        console.log("Loaf video uploaded!") 
    }) 
    typeTweet(); 
    addEmoji(); 
}
Illustration of a code snippet appearing on a web browser-like interface.
A graphical representation of code execution steps in a browser-like window, showing the function call stack with one entry labeled `createLoafTweet()`.
Diagram of a call stack showing the functions postTwitterUpload() and createLoafTweet() being executed.
Illustration of a web browser window with code execution flow. A flowchart with an arrow from "call stack" to "Fetch API" depicting "createLoafTweet()" calling "postTwitterUpload()".
The slide contains a stylized web browser window with a JavaScript code snippet, flowchart elements representing the Fetch API, Call Stack, and Event Queue. The flowchart illustrates the process of creating a tweet, with elements labeled as 'typeTweet()', 'createLoafTweet()', and 'postTwitterUpload()'.
Illustration of the event loop with a call stack including a function, a fetch API with a loading symbol, and an event queue.

Diagram illustrating the event loop process including call stack, Fetch API, and event queue. The call stack shows functions being executed, the Fetch API is represented by a hexagon shape with an hourglass and the postTwitterUpload() function inside it, and there's an event queue box on the right.

A visual representation of the event loop including the Call Stack, Fetch API, and Event Queue. The Call Stack shows the function createLoafTweet() being called, the Fetch API shows the function postTwitterUpload(), and the Event Queue is empty.
Illustration of a browser window with code and event loop components, including a call stack, event queue, and fetch API with a waiting period of 20 seconds represented by an hourglass icon.
Diagram showing the Event Loop with the Call stack, Fetch API, and Event Queue.
Diagram illustrating the Event Loop with labels for "Fetch API", "Call stack", and "Event Queue". The call stack shows a .then() block, which is connected to the Event Queue via an Event Loop arrow.
Diagram illustrating the Event Loop involving a function createLoafTweet, a Call Stack, Event Queue, and a Fetch API.

What is the event loop?

Call stack

Web API

  • event loop is constantly checking the call stack to see if its empty
  • if it is, it will push the first function from the event queue into the call stack
Diagram showing the event loop process, including call stack, Web API, and event queue interactions.

Exploring the Event Loop

How you interact with it

  • Anything asynchronous and you start tangibly interacting with the event loop!
  • setTimeouts, promises, async/await, callbacks, are all things that easily display the true nature of the event loop

Event Loop Simulation

A browser window illustration with two pixel art cats. One cat is red, and the other is a brown cat wearing a chef's hat.

Call Stack

Web API

Order Loaf

Event Queue

An animated illustration of the event loop. Ikram describes.

Exploring the Event Loop

How to queue animations one after the other?

function move() {
        const moveToButtonKeyframes = [
            { transform: `translate(${currentCoords})` },
            { transform: `translate(${buttonCoords})` },
        ];

        const animationOptions = {
            duration: 3000,
            easing: "ease",
        };

        cat.animate(moveToButtonKeyframes, animationOptions);

        // This doesn't wait for the previous animation, and starts animating immediately
        cat.animate(moveToStackKeyframes, animationOptions)
    }
Failed initial approach to queuing animations one after the other

How to queue animations one after the other?

cat.animate(moveToButtonKeyframes, animationOptions);
		
		// This doesn't wait for the previous animation, and starts animating immediately
cat.animate(moveToStackKeyframes, animationOptions);
Failed initial approach to queuing animations one after the other

How to queue animations one after the other?

Failed initial approach to queuing animations one after the other
A graphical depiction titled 'Exploring the Event Loop' showing a web browser window with sections labeled 'Call Stack', 'Web API', and 'Event Queue'. It includes illustrations of a red creature and a loaf of bread with 'orderLoaf()' and 'Order Loaf' text.

How to queue animations one after the other?


cat.animate(moveToButtonKeyframes, animationOptions).finished.then(() => {
  cat.animate(moveToStackKeyframes, animationOptions);
});
    

Success using .then()

  • Allows you to purposefully block the event loop

How to queue animations one after the other?

async function move() {
await cat.animate(moveToButtonKeyframes, animationOptions).finished;
await cat.animate(moveToStackKeyframes, animationOptions).finished;
}
Success using async/await

How do other languages implement concurrent multitaskin

Multithreading as an alternative

  • Multi-threading is when within a process, multiple threads are being executed in 'parallel'
  • For eg: use one thread to handle incoming requests, and another thread to handle CPU intensive work

Multithreading > Event loop

  • Imagine you've implemented a search field, where on every key press, you iterate over a large amount of data to find the search result
  • This leads to a very laggy experience when typing because the function invocations will stay primarily in the call stack and not handed off to a web API

Multithreading > Event loop

Event Loop

Stylised input field that contains 'loaf is cute'

Event Loop > Multithreading

  • Way simpler! More predictable!
  • No switching threads randomly in the middle of executing a function
  • Predict exact order of execution
Illustration of a person meditating while seated cross-legged meditating.

Is it parallel?

  • Not in the true sense -- multithreading does not require multiple CPU cores
  • But to you as a programmer, it may as well be -- the computer handles the context switching for you at the CPU level

Exploring the Event Loop

Is JS sequential?

  • Yes -- no two things are happening at exactly the same time in JavaScript
  • It is always one after the other
  • This is far simpler than true parallelism, as well as multithreading

Get to know me <3

  • I’m a software engineer at an EdTech company called Stile Education!
  • Twitter: @ikramsaedi
  • GitHub: ikramsaedi
  • Event Loaf Simulation:
https://ikramsaedi.github.io/loaf-event-loop/
A photo of a cat wearing a bandana, labeled "Loaf".