JS Basic concepts that some people miss
Here is the list of things we will cover Promises in Depth Throttling vs Debouncing Event Capturing, Bubbling & Propagation Concurrency & how to avoid data conflicts JS Strict Mode Prototype in JS Promises Promise is JS Object that repersents the eventual completion or failure of an async process. A promise has 3 stage Pending Fullfilled Rejected It make our async code more clean and readable than callbacks. Callbacks leds to callback hell, which make the code more harder to debug and read. // Here is an example of callback hell // Case : I need to get orders of all the users & generate a report from it. function getUsers(callback) { setTimeout(() => { console.log("User Fetched"); callback(); }, 3000); } function getOrders(callback) { const orders = [ { order: "#31411", user: "Adam", items: ["Pizza", "Juice"] } ]; setTimeout(() => { console.log("Orders fetched"); callback(orders); }, 3000); } function generateReport(orders, callback) { setTimeout(() => { console.log("Report Generated for", orders); callback(); }, 3000); } getUsers(() => { getOrders((orders) => { generateReport(orders, () => { console.log("Successfully completed all tasks"); }); }); }); // Here is how you use Promise const myPromise = new Promise((resolve,reject)=>{ let success = true; const data = { name:"Jayant", } setTimeout(()=>{ if(success){ resolve(data); }else{ reject("Error while fetching"); } },2000) }) // resolve(value) -> it marks the promise as fullfilled and pass the value. // reject(error) -> it marks the promise as rejected and passes error. myPromise.then((res)=>{ console.log("data",res); }).catch((err)=>{ console.error("Error",err); }) // Let's take above example but using promise function getUsers() { return new Promise((res,rej)=>{ setTimeout(()=>{ res("Data Feteched") },2000) }) } function getOrders() { const orders = [ { order: "#31411", user: "Adam", items: ["Pizza", "Juice"] } ]; return new Promise((res,rej)=>{ setTimeout(()=>{ res(orders) },2000) }) } function generateReport(orders) { return new Promise((res,rej)=>{ setTimeout(()=>{ res("Report Generated") },2000) }) } getUsers() .then((res)=>{ console.log(res); return getOrders(); }) .then((res)=>{ console.log(res); return generateReport(res); }) .then((res)=>{ console.log(res); }) .catch((err)=>{ console.error("Error",err); }) Promises Method Promise.all Runs Multiple promises in parallel and waits for all to complete Returns single promise Fullfilled if all promises successed. Rejected if any promise fails. // SYNTAX Promise.all([promise1,promise2,promise3]) .then(result=> console.log(result)) .catch(err=>console.log(err)) Promise.allSettled Runs Multiple promises in parallel Returns and array of object with each promise status No Failures are lost. // SYNTAX Promise.allSettled([promise1,promise2,promise3]) .then(res=>console.log(res)); Promise.race Runs Multiple promises in parallel Returns only the 1st promise that resolves or rejects. Only the fast one happens. // SYNTAX Promise.race([promise1,promise2,promise3]) .then(result=> console.log("Success",result)) .catch(err=>console.log("Total Failure",err)) Promise.any Runs Multiple promises in parallel Returns the first fullfilled promise. if all fails, it then returns an AggregateError Useful when we want to fetch same thing from multiple servers. Promise.any([promise1, promise2, promise3]) .then(result => console.log("First successful:", result)) .catch(error => console.log("All failed:", error)); Throttling vs Debouncing Throttling : It is an optimization technique, that allow us to limit the execution of a function so that it runs at most once in a specified period. Usecase Window Resize API rate limit Scrolling event Basically Throttling limits the execution of a function to once in an interval. // Implementating Throttling function Throttle(func,wait){ let time = 0; return function(...args){ let currTime = Date.now(); if(currTime-time>wait){ func.apply(this,args); } } } Debouncing : It is an optimization technique, that delays execution of a function until inactivity. Usecase Search Input Form Validation // Implementing debouncing function debounce(func,wait){ let timeout:NodeJS.timeout | undefind; // we are using anonymous fuction rather than arrow functions as in objects this ref

Here is the list of things we will cover
- Promises in Depth
- Throttling vs Debouncing
- Event Capturing, Bubbling & Propagation
- Concurrency & how to avoid data conflicts
- JS Strict Mode
- Prototype in JS
Promises
Promise
is JS Object that repersents the eventual completion or failure of an async process.
A promise has 3 stage
- Pending
- Fullfilled
- Rejected
It make our async code more clean and readable than callbacks
. Callbacks leds to callback hell, which make the code more harder to debug and read.
// Here is an example of callback hell
// Case : I need to get orders of all the users & generate a report from it.
function getUsers(callback) {
setTimeout(() => {
console.log("User Fetched");
callback();
}, 3000);
}
function getOrders(callback) {
const orders = [
{
order: "#31411",
user: "Adam",
items: ["Pizza", "Juice"]
}
];
setTimeout(() => {
console.log("Orders fetched");
callback(orders);
}, 3000);
}
function generateReport(orders, callback) {
setTimeout(() => {
console.log("Report Generated for", orders);
callback();
}, 3000);
}
getUsers(() => {
getOrders((orders) => {
generateReport(orders, () => {
console.log("Successfully completed all tasks");
});
});
});
// Here is how you use Promise
const myPromise = new Promise((resolve,reject)=>{
let success = true;
const data = {
name:"Jayant",
}
setTimeout(()=>{
if(success){
resolve(data);
}else{
reject("Error while fetching");
}
},2000)
})
// resolve(value) -> it marks the promise as fullfilled and pass the value.
// reject(error) -> it marks the promise as rejected and passes error.
myPromise.then((res)=>{
console.log("data",res);
}).catch((err)=>{
console.error("Error",err);
})
// Let's take above example but using promise
function getUsers() {
return new Promise((res,rej)=>{
setTimeout(()=>{
res("Data Feteched")
},2000)
})
}
function getOrders() {
const orders = [
{
order: "#31411",
user: "Adam",
items: ["Pizza", "Juice"]
}
];
return new Promise((res,rej)=>{
setTimeout(()=>{
res(orders)
},2000)
})
}
function generateReport(orders) {
return new Promise((res,rej)=>{
setTimeout(()=>{
res("Report Generated")
},2000)
})
}
getUsers()
.then((res)=>{
console.log(res);
return getOrders();
})
.then((res)=>{
console.log(res);
return generateReport(res);
})
.then((res)=>{
console.log(res);
})
.catch((err)=>{
console.error("Error",err);
})
Promises Method
-
Promise.all
- Runs Multiple promises in parallel and waits for all to complete
- Returns single promise
-
Fullfilled
if all promises successed. -
Rejected
if any promise fails.
-
// SYNTAX Promise.all([promise1,promise2,promise3]) .then(result=> console.log(result)) .catch(err=>console.log(err))
-
Promise.allSettled
- Runs Multiple promises in parallel
- Returns and array of object with each promise status
- No Failures are lost.
// SYNTAX Promise.allSettled([promise1,promise2,promise3]) .then(res=>console.log(res));
-
Promise.race
- Runs Multiple promises in parallel
- Returns only the 1st promise that
resolves or rejects
. - Only the fast one happens.
// SYNTAX Promise.race([promise1,promise2,promise3]) .then(result=> console.log("Success",result)) .catch(err=>console.log("Total Failure",err))
-
Promise.any
- Runs Multiple promises in parallel
- Returns the first fullfilled promise.
- if all fails, it then returns an
AggregateError
- Useful when we want to fetch same thing from multiple servers.
Promise.any([promise1, promise2, promise3]) .then(result => console.log("First successful:", result)) .catch(error => console.log("All failed:", error));
Throttling vs Debouncing
Throttling
: It is an optimization technique, that allow us to limit the execution of a function so that it runs at most once in a specified period.
Usecase
- Window Resize
- API rate limit
- Scrolling event
Basically Throttling limits the execution of a function to once in an interval.
// Implementating Throttling
function Throttle(func,wait){
let time = 0;
return function(...args){
let currTime = Date.now();
if(currTime-time>wait){
func.apply(this,args);
}
}
}
Debouncing
: It is an optimization technique, that delays execution of a function until inactivity.
Usecase
- Search Input
- Form Validation
// Implementing debouncing
function debounce(func,wait){
let timeout:NodeJS.timeout | undefind;
// we are using anonymous fuction rather than arrow functions as in objects this refers to the object, but in case of arrow function this refer to the surrounding scope (not the object) [Likely window].
return function(...args){
if(timeout){
timeout.clearTimeout();
}
setTimeout(()=>{
func.apply(this,args);
},wait)
}
}
Event Capturing, Bubbling & Propagation
Event Propagation
- It is process of an event travelling through the DOM.
It has 3 Phases
-
Event Capturing
- In this phase event moves from root node to target node.
- By Default handlers are not invoked in this phase.
- If you want to call some handler you have to do this
// it takes 3 parameter - eventName, handler , useCapture div.addEventListener("click",func,true);
- One useful usecase of it can be you want to do something before some event got triggered.
-
Target
- In this phase the traget node handler runs.
-
Event Bubbling
- In this phase event moves from target node to root node.
- Here all the handler attached to the parents runs.
- if you want to stop the event propagation, do this.
event.stopPropagation()
-
Event Delegation
: Instead of applying handlers to multiple child elements, we only apply handler to parent node. This technique is called event delegation.
Concurrency
It refers to multiple process or thread are executing at the same time.
Example
- Multiple transaction update the data at same time.
- Multiple servers try to update the same DB Concurrently.
If 2 process try to update the field at same time then, it can lead to data inconsitency and race conditions.
Ways to handle this
- Locking : A process first aquire the lock then update it, other processes unable to access the data till the lock is released. (This can cause performance issue.)
- DB Tranactions and Isolation Levels : DB has Isolation levels to solve Concurrency problem.
ISOLATION LEVELS
Read Uncommited - Txns can read Uncommited changes
Read Commited - Txns can only read commited chages
Repeatable Read - Txn read the save value even if it is changed
Serializable - It prevents Dirty read [Can't read Uncommited changes] , No Non-Repeatable Reads [ once a txn reads it , no other txn can access it until the prv txn commits or rollback], the set of rows is locked, no new rows can appear [Phantom Reads], one transaction must complete before another can modify the same data.
Serializable is best to solve Concurrency issue but operations are much slower in this.
JS Strict Mode
This mode basically enforces certain set of rules that made our code more bug free.
"use strict"
// In strict mode, this is undefined for global
// Inside a regular function this is also undefined.
// Rest Same
Prototype in JS
Every JS Object has a special property call prototype
.
The prototype is a blueprint that contains properties and methods shared by all instances of that object.
When an object is created from a constructor function, it automatically inherits the properties and methods from its prototype.