🟡 **I JavaScript Asynchronous Diagram**
!Illustration image
On this page
🟡 I JavaScript Asynchronous Diagram

| Component | Description |
|---|---|
| Memory Heap | Where variables and objects are stored. |
| Call Stack | Where synchronous JS code is executed (LIFO – Last In, First Out). |
| Web APIs | Asynchronous APIs provided by browser (DOM, AJAX, Timer, ...). |
| Callback Queue | Queue for callbacks from Web APIs after completion (Task Queue / Macro-task). |
| Event Loop | Continuously checks Call Stack and pushes tasks from the Queue when the Stack is empty. |
🚦 How the Flow Works
The event loop is a concept within the JavaScript runtime environment regarding how asynchronous operations are executed within JavaScript engines. It works as such:
- The JavaScript engine starts executing scripts, placing synchronous operations on the call stack.
- When an asynchronous operation is encountered (e.g.,
setTimeout(), HTTP request), it is offloaded to the respective Web API or Node.js API to handle the operation in the background. - Once the asynchronous operation completes, its callback function is placed in the respective queues – task queues (also known as macrotask queues / callback queues) or microtask queues. We will refer to "task queue" as "macrotask queue" from here on to better differentiate from the microtask queue.
- The event loop continuously monitors the call stack and executes items on the call stack. If/when the call stack is empty:
- Microtask queue is processed. Microtasks include promise callbacks (
then,catch,finally),awaitcontinuations,MutationObservercallbacks, and calls toqueueMicrotask(). The event loop takes the first callback from the microtask queue and pushes it to the call stack for execution. This repeats until the microtask queue is empty. - Macrotask queue is processed. Macrotasks include web APIs like
setTimeout(), HTTP requests, user interface event handlers like clicks, scrolls, etc. The event loop dequeues the first callback from the macrotask queue and pushes it onto the call stack for execution. However, after a macrotask queue callback is processed, the event loop does not proceed with the next macrotask yet! The event loop first checks the microtask queue. Checking the microtask queue is necessary as microtasks have higher priority than macrotask queue callbacks. The macrotask queue callback that was just executed could have added more microtasks!- If the microtask queue is non-empty, process them as per the previous step.
- If the microtask queue is empty, the next macrotask queue callback is processed. This repeats until the macrotask queue is empty.
- Microtask queue is processed. Microtasks include promise callbacks (
- This process continues indefinitely, allowing the JavaScript engine to handle both synchronous and asynchronous operations efficiently without blocking the call stack.
Note:
- JavaScript has only one Call Stack (single-threaded), but thanks to this mechanism, it can handle multiple asynchronous tasks smoothly.
- Callback Queue ≈ Task Queue (macro-task).
- Microtask Queue (Promise, MutationObserver, ...) has higher priority than Callback Queue but is not shown in this diagram. Event loop always processes tasks in Microtask Queue first whenever Call Stack is empty, then continues to process Macrotask Queue.
🟡 II How to Use this in JavaScript (with example explanations)
Below is a detailed roundup of how this is used and what it means in JavaScript, based on verified sources from MDN Web Docs – this and the ECMAScript specification:
1. What Is this?
this is a special keyword in JavaScript that represents the current execution context - specifically, the object through which a function is being called.
2. The Meaning of this Depends on How the Function Is Called
a. In a regular function (non-strict mode)
function show() {
console.log(this);
}
show(); // this === window (browser) or global (Node.js)
When you call a regular function in non-strict mode, this defaults to the global object (window in the browser, global in Node.js).
b. In strict mode
"use strict";
function show() {
console.log(this);
}
show(); // this === undefined
In strict mode, calling a regular function makes this be undefined instead of referring to the global object.
c. In an object method
const obj = {
name: "Loi",
show: function () {
console.log(this.name);
},
};
obj.show(); // this === obj => 'Loi'
When you call a method through an object (obj.show()), this points to that object itself (obj), so this.name prints 'Loi'.
d. In a constructor function
When using new, the function creates a new object and this inside the function points to that new object.
function Person(name) {
this.name = name;
}
const p = new Person("Loi");
console.log(p.name); // 'Loi', this === p
e. In a class (ES6)
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name);
}
}
const dog = new Animal("Muc");
dog.speak(); // this === dog => 'Muc'
Similar to a constructor function, this inside a class points to the newly created instance, so this.name accesses the object's name.
3. Explicit Binding
Explicit binding is when you force a function to use a specific object as this. You do this using three built-in methods: call, apply, and bind.
function greet() {
console.log("Hello", this.name);
}
const user = { name: "Loi" };
greet.call(user); // Hello Loi
greet.apply(user); // Hello Loi
const greetUser = greet.bind(user);
greetUser(); // Hello Loi
call, apply, and bind let you explicitly specify the value of this when calling a function.
callandapplyinvoke the function immediately withthisset touser.bindreturns a copy of the function withthispermanently fixed touser.
4. this in Arrow Functions
- Arrow functions don't have their own
thiscontext. thisinside an arrow function is taken from the nearest enclosing function.
const obj = {
name: "Loi",
show: function () {
const arrow = () => {
console.log(this.name);
};
arrow();
},
};
obj.show(); // 'Loi'
The arrow function has no this of its own - it "inherits" this from its enclosing function (show).
Since show is a method on obj, this.name is still 'Loi'.
5. Some Special Cases
a. Passing a method as a callback
When you pass an object's method directly to another function (like setTimeout), the object's context is lost, so this no longer points back to obj.
const obj = {
name: "Loi",
show: function () {
console.log(this.name);
},
};
setTimeout(obj.show, 1000); // undefined (in strict mode) or window.name if not strict
Solution: use an arrow function or bind:
Using an arrow function or bind keeps this correctly pointing to obj.
setTimeout(() => obj.show(), 1000);
or
setTimeout(obj.show.bind(obj), 1000);
6. In a DOM Event Handler
When handling a DOM event with a regular function (not an arrow function), this points to the DOM element that triggered the event.
const btn = document.querySelector("button");
btn.onclick = function () {
console.log(this); // this === btn
};
7. this Quick-Reference Table
| How it's called | What is this? |
|---|---|
| Regular function (non-strict) | The global object (window/global) |
| Regular function (strict mode) | undefined |
| A method on an object | That object itself |
Constructor (using new) | The newly created object |
| Arrow function | this from the enclosing scope |
Using call, apply, bind | The object passed in |
| DOM event handler | The DOM element that triggered the event |
Sources:
