Understanding Event Loop: a React approach

MarcoZee
3 min readNov 10, 2021

--

When you first encounter the concept of event loop in JS, you might bump into MDN page of such a topic, the same as I do. I felt pumped before but rather disappointed after, for it doesn’t suffice our arduous learning journey of JS. So I dug deeper, trying to understand the real meat behind this topic. If you are just like me who love to explore what’s under the hood, this article is for you.

First of all, event loop mostly likely concerns queue: what message is sent first and what’s next etc. Here’s an example of queue:

try {console.log("This should be the first message");}catch(e) {console.log("This message will never be run");}finally {console.log("This should come last");}\\ =>This should be the first message\\ =>This should come last

The example given lines up a queue synchronously , which can fulfill most of simple daily chores. But what if we need to run asynchronous code, for instance, creating a promise, or maybe setting a timeout?

Before we jump into the code, let me introduce some important theories about queuing: microtask and macrotask queue. As the name suggests, one is for bigger task while another for smaller task. For example, setTimeout and setInterval are typical macrotask methods , while promise and async function are considered microtask bound, and one macro may contain many micros. Most importantly, macrotask is only executed after all microtasks from last macrotask finalized.

setTimeout(()=> console.log("This represents a macrotask"));//One big taskPromise.resolve().then(()=>{console.log("This is the first microtask");console.log("Another micro");})//One smaller task with 2 minitasks// =>This is the first microtask// =>Another micro// =>This represents a macrotask

It’s crystal clear as the pattern illustrated this way. But how about we jumble both sync and async snippets together? What’s the queue right now? I’ll flex another example to explain a real-world scenario before we get to that part.

Assume I’m to implement a dynamic phonebook with React. Something like this:

A simple Phonebook app with React

Usually in this situation, adding a addName function in App.js can be described like this:

function addName(e) {e.preventDefault();const target = persons.find((person) => person.name === newName);console.log(target);if (target) {if (window.confirm("It exists. You sure to update the number?")) {const id = target.id;console.log(id);updateNumber(id, target);} else return 0;}const nameObject = {name: newName,number: newNumber};phoneService.create(nameObject).then((returnedObject) => {setPersons(persons.concat(returnedObject));setNewName("");setNewNumber("");}).then(() => {setMessage("New person added!");setTimeout(() => {setMessage(null);}, 5000);});}

I would not throw light on the code in detail at this point since it’s not our focus in this article.

We notice that setTimeout is invoked after setMessage hook is complete, and this is logical, because we don’t want to announce we had added a person successfully to the phonebook before we actually added such person. However, there is another more handy way to do this, and what if we hoist setTimeout even before phoneService fetch?

setTimeout(() => {setMessage(null);}, 5000);//hoisted setTimeout//rest is the samephoneService.create(nameObject).then((returnedObject) => {setPersons(persons.concat(returnedObject));setNewName(“”);setNewNumber(“”);}).then(() => {setMessage(“New person added!”);});
Even setTimeout is hoisted it still works wonders

It still works perfectly! You might wonder what’s going on here. This macrotask always queues last no matter what position it is in a task.

Let’s fulfill the promise I made one minute ago. We make a salad out of first two examples I showed in this article:

try {Promise.resolve().then(()=>{console.log(“This is the first microtask”);console.log(“Another micro”);}).then(()=>setTimeout(()=> console.log(“This represents a macrotask”)));}
catch(e) {
console.log(“Is there any error here?”);}finally {console.log(“Is this the last task we run?”);}// =>Is this the last task we run?// =>This is the first microtask// =>Another micro// =>This represents a macrotask

Unsurprisingly, the program follows a pattern as sync first async second, meanwhile in async tasks, micro first macro second.

To recap, for an event loop, sync invocation => microtasks => macrotask

If you wanna know more about more advanced React and JS topics, subscribe me.

--

--

MarcoZee

Functional programmer | Create software that lasts