JavaScript for Backend
- JavaScript powers backend development in Node.js through its execution context and event loop. This content explains how asynchronous operations work using callbacks, promises, and async/await, enabling efficient handling of server-side tasks.
🔹 Execution Context
An Execution Context is the environment where JavaScript code is prepared and executed.
Whenever JavaScript runs a piece of code, it creates an execution context for it.There are three main things inside an execution context:
Variables
Functions
The value of this
When a JavaScript program starts, a Global Execution Context is created first.
Function Call and Variable Passing in JavaScript
This code demonstrates how a variable is passed to a function in JavaScript. The value of x is sent as an argument to the multiply function, which processes it and returns the result after multiplying the number by 2.
var x = 5;
function multiply(num) {
return num * 2;
}
multiply(x);
Step 1: Global Execution Context Created
Memory is allocated:
x → undefined
multiply → function stored
Step 2: Code Execution Phase
x gets value 5
multiply(x) is called
Step 3: Function Execution Context Created
New execution context for multiply
num → 5
Code executes → returns 10
Step 4: Execution Context Destroyed
Function execution context removed
Control returns to global context
🔹 Call Stack
The Call Stack is a data structure that keeps track of execution contexts.
It follows the Last In, First Out (LIFO) rule.
Call Stack in JavaScript (LIFO Principle)
The Call Stack is a data structure that tracks the order of function execution in JavaScript. It follows the LIFO (Last In, First Out) rule, where the most recently called function is executed first. In this example, first() is added to the stack, then second() runs and completes before control returns back.
function first() {
second();
}
function second() {
console.log("Hello");
}
first();
🔹 Event Loop
JavaScript is single-threaded, but it can handle multiple tasks using the Event Loop.
The Event Loop:
Manages asynchronous operations
Decides when code moves to the call stack
Event Loop in JavaScript
The Event Loop manages asynchronous operations in JavaScript and controls when callback code is moved to the call stack. In this example, "Start" and "End" are logged first, while "Timeout" is executed later after the delay, showing how the Event Loop handles non-blocking code execution.
console.log("Start");
setTimeout(() => {
console.log("Timeout");
}, 2000);
console.log("End");
🔹 Callbacks
A callback is a function passed as an argument to another function and executed later.
Callbacks in JavaScript
A callback is a function that is passed as an argument to another function and executed later. In this example, the greet function calls the callback after greeting the user, showing how callbacks allow code to run after a specific task is completed.
function greet(name, callback) {
console.log("Hello " + name);
callback();
}
greet("John", function () {
console.log("Welcome!");
});
🔹 Promises
A Promise represents a value that will be available in the future.
It helps manage asynchronous operations more cleanly.A promise has three states:
Pending
Fulfilled
Rejected
Promises and Their States in JavaScript
A Promise represents the result of an asynchronous operation and can be in one of three states: Pending, Fulfilled, or Rejected. In this example, the promise is resolved when the operation succeeds and handled using .then(), while errors are managed using .catch().
const promise = new Promise((resolve, reject) => {
let success = true;
if (success) {
resolve("Data received");
} else {
reject("Error occurred");
}
});
promise
.then(result => console.log(result))
.catch(error => console.log(error));
🔹 Async / Await
async and await are used to write promise-based code in a simpler way.
Async/Await in JavaScript
This code demonstrates how async/await simplifies working with Promises. The getData() function returns a Promise, and fetchData() waits for it to resolve using await, making asynchronous code easier to read and write like synchronous code.
function getData() {
return new Promise(resolve => {
setTimeout(() => {
resolve("Data loaded");
}, 2000);
});
}
async function fetchData() {
const result = await getData();
console.log(result);
}
fetchData();
Why Use Async/Await?
Cleaner syntax
Easier to read
Avoids callback chaining