Javascript concept every developer should know!!!
Tags: javascript, productivity, beginners, programming
Published: 2022-10-01 16:48:29

I have gathered important points that can be revisited for quick recall of JS concepts.

## 1. Call Stack
It’s a data structure which records the function calls, basically where in the program we are. If we call a function to execute , we push something on to the stack, and when we return from a function, we pop off the top of the stack.

```
function greeting() {
  // [1] Some code here
  sayHi();
  // [2] Some code here
}
function sayHi() {
  return "Hi!";
}

// Invoke the `greeting` function
greeting();

// [3] Some code here

```


**The code above would be executed like this:**
1. Ignore all functions, until it reaches the `greeting()` function invocation.
2. Add the `greeting()` function to the call stack list.
3. Execute all lines of code inside the `greeting()` function.
4. Get to the `sayHi()` function invocation.
5. Add the `sayHi()` function to the call stack list.
6. Execute all lines of code inside the `sayHi()` function, until reaches its end.
7. Return execution to the line that invoked `sayHi()` and continue executing the rest of the `greeting()` function.
8. Delete the `sayHi()` function from our call stack list.
9. When everything inside the `greeting()` function has been executed, return to its invoking line to continue executing the rest of the JS code.
10. Delete the `greeting()` function from the call stack list.

**In summary**
The key takeaways from the call stack are:
1. It is single-threaded. Meaning it can only do one thing at a time.
2. Code execution is synchronous.
3. A function invocation creates a stack frame that occupies a temporary memory.
4. It works as a LIFO — Last In, First Out data structure.

---

## 2. Primitive Types

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h21gw3w80blnejnd1gf5.png)

1. Primitive values
2. Non-primitive values or Composite(object references)

Data types that are known as primitive values in JavaScript are numbers, strings, booleans, null, undefined. Objects such as functions and arrays are referred to as non-primitive values.

The fundamental difference between primitives and non-primitives is that primitives are immutable(cannot be ) and non-primitives are mutable.

<u>PRIMITIVES</u>

Primitives are known as being immutable data types because there is no way to change a primitive value once it gets created.

```
var string = 'This is a string.';
string[1] = 'H'console.log(string)
// 'This is a string.'
```
Primitives are compared by value. Two values are strictly equal if they have the same value.

```
var number1 = 5;
var number2 = 5;
number1 === number 2; // true
var string1 = 'This is a string.';
var string2 = 'This is a string.';
string1 === string2; // true

```
Here the variable for primitives stores the value, so they are always copied or passed by value.

<u>NON-PRIMITIVES</u>

Non-primitive values are mutable data types. The value of an object can be changed after it gets created.

```
var arr = [ 'one', 'two', 'three', 'four', 'five' ];
arr[1] = 'TWO';
console.log(arr) 
// [ 'one', 'TWO', 'three', 'four', 'five' ];
```
Objects are not compared by value. This means that even if two objects have the same properties and values, they are not strictly equal. Same goes for arrays. Even if they have the same elements that are in the same order, they are not strictly equal.

```
var obj1 = { 'cat': 'playful' };
var obj2 = { 'cat': 'playful' };
obj1 === obj2;  // false
var arr1 = [ 1, 2, 3, 4, 5 ];
var arr2 = [ 1, 2, 3, 4, 5 ];
arr1 === arr2;  // false
```
Non primitive values can also be referred to as reference types because they are being compared by reference instead of value. Two objects are only strictly equal if they refer to the same underlying object.

```
var obj3 = { 'car' : 'purple' }
var obj4 = obj3;obj3 === obj4;  // true
```
You can check if two objects are the same by doing a deep equals comparison to go through each of the properties to determine if two objects have the exact same properties.

Here the variables for non-primitives only store references of those objects. So they will always be copied or passed by reference.

---

## 3. Value Types and Reference Types
<u>Primitive Types</u>
The in-memory value of a primitive type is it's actual value (e.g. boolean true, number 42). A primitive type can be stored in the fixed amount of memory available.

> null
> undefined
> Boolean
> Number
> String
> Primitive types are also known as: scalar types or simple types.

<u>Reference Types</u>
A reference type can contain other values. Since the contents of a reference type can not fit in the fixed amount of memory available for a variable, the in-memory value of a reference type is the reference itself (a memory address).

> Array
> Object
> Function
Reference types are also known as: complex types or container types.

Code Examples
Copying a primitive:

```
var a = 13         // assign `13` to `a`
var b = a          // copy the value of `a` to `b`
b = 37             // assign `37` to `b`
console.log(a)     // => 13
```
The original was not changed, we can only change the copy.

Copying a reference:

```
var a = { c: 13 }  // assign the reference of a new object to `a`
var b = a          // copy the reference of the object inside `a` to new variable `b`
b.c = 37           // modify the contents of the object `b` refers to
console.log(a)     // => { c: 37 }
```
The original was also changed, since the reference got copied.

---

## 4. Implicit, Explicit, Nominal, Structuring and Duck Typing

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmm5z8xaismskbs41nd1.png)

Type Coercion refers to the process of automatic or implicit conversion of values from one data type to another. This includes conversion from Number to String, String to Number, Boolean to Number etc. when different types of operators are applied to the values.

In case the behavior of the implicit conversion is not sure, the constructors of a data type can be used to convert any value to that datatype, like the Number(), String() or Boolean() constructor.

For eg:

```
String(123) // explicit
123 + ''    // implicit
```

---

## 5. == vs === vs typeof
JavaScript provides both strict(===, !==) and type-converting(==, !=) equality comparison. The strict operators take type of variable in consideration, while non-strict operators make type correction/conversion based upon values of variables. The strict operators follow the below conditions for different types,

Two strings are strictly equal when they have the same sequence of characters, same length, and same characters in corresponding positions.
Two numbers are strictly equal when they are numerically equal. i.e, Having the same number value. There are two special cases in this,
NaN is not equal to anything, including NaN.
Positive and negative zeros are equal to one another.
Two Boolean operands are strictly equal if both are true or both are false.
Two objects are strictly equal if they refer to the same Object.
Null and Undefined types are not equal with ===, but equal with ==. i.e, null===undefined --> false but null==undefined --> true

Some of the example which covers the above cases,

```
0 == false   // true
0 === false  // false
1 == "1"     // true
1 === "1"    // false
null == undefined // true
null === undefined // false
'0' == false // true
'0' === false // false
[]==[] or []===[] //false, refer different objects in memory
{}=={} or {}==={} //false, refer different objects in memory
```

---

## 6. Function Scope, Block Scope and Lexical Scope

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3z3ecs7rni1h9qxz0e4.png)
Variable scope is the location where a variable is defined and the context where other pieces of your code can access and manipulate it. In other words, the variable scope defines where your variables can be obtained to work with it either to be displayed or do arithmetic operations on it. Function, block, and lexical scopes are going to be discussed throughout this article.

<u>Function Scope</u>
Function scope is where the variable is visible only within a function, and it cannot be accessed outside the curly brackets of the function. In javascript, var is the keyword that is used to declare a variable for a function scope accessibility.

<u>Block Scope</u>
Block Scope is the area within if, switch conditions and for, while loops. In ES6, const and let are the keywords that are used to define variables for a block scope accessibility, which means that those variables exist only within the corresponding block.

<u>Lexical Scope</u>
Lexical scope means that the childrens' scope has access to the variables declared in the parent scope, so if we have 2 nested functions, the inner function can access the variable declared in the outer function using any of the keywords used in javascript either with var, let or const. This means that the children's functions are lexically bound to their parents.

---

## 7. Expression vs Statement

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/enwbxww4b90rbq39e7hx.png)


JavaScript distinguishes expressions and statements. An expression is any valid unit of code that resolves to a value. A statement is a unit of code that performs an action.
But its necessary to understand:
1. Expressions return value, statements do not.
2. All expressions are statements, but not otherwise. You cannot use a statement in place of an expression.
Some examples:

<u>1. Statements</u>
```
let x = 0;
function add(a, b) { return a + b; }
if (true) { console.log('Hi'); }
```

<u>2. Expressions</u>
```
x;          // Resolves to 0
3 + x;      // Resolves to 3
add(1, 2);  // Resolves to 3
```
Anywhere JavaScript expects a statement, you can also write an expression. This kind of statement is called an expression statement. Conversely, you cannot write a statement where JavaScript expects an expression.

---

## 8. IIFE, Modules and Namespaces
<u>IIFE(Immediately Invoked Function Expression)</u>
IIFE (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it is defined. The signature of it would be as below,

```
(function () {
  // logic here
})();
```
The primary reason to use an IIFE is to obtain data privacy because any variables declared within the IIFE cannot be accessed by the outside world. i.e, If you try to access variables with IIFE then it throws an error as below,

```
(function () {
  var message = "IIFE";
  console.log(message);
})();
```
console.log(message); //Error: message is not defined

<u>Modules</u>
Modules refer to small units of independent, reusable code and also act as the foundation of many JavaScript design patterns. Most of the JavaScript modules export an object literal, a function, or a constructor

<u>Namespace</u>
Even though JavaScript lacks namespaces, we can use Objects , IIFE to create namespaces.

1. Using Object Literal Notation: Let's wrap variables and functions inside an Object literal which acts as a namespace. After that you can access them using object notation

```
var namespaceOne = {
   function func1() {
       console.log("This is a first definition");
   }
}
var namespaceTwo = {
     function func1() {
         console.log("This is a second definition");
     }
 }
namespaceOne.func1(); // This is a first definition
namespaceTwo.func1(); // This is a second definition
```
2. Using IIFE (Immediately invoked function expression): The outer pair of parentheses of IIFE creates a local scope for all the code inside of it and makes the anonymous function a function expression. Due to that, you can create the same function in two different function expressions to act as a namespace.

```
(function () {
  function fun1() {
    console.log("This is a first definition");
  }
  fun1();
})();

(function () {
  function fun1() {
    console.log("This is a second definition");
  }
  fun1();
})();
```
3. Using a block and a let/const declaration: In ECMAScript 6, you can simply use a block and a let declaration to restrict the scope of a variable to a block.

```
{
  let myFunction = function fun1() {
    console.log("This is a first definition");
  };
  myFunction();
}
//myFunction(): ReferenceError: myFunction is not defined.

{
  let myFunction = function fun1() {
    console.log("This is a second definition");
  };
  myFunction();
}
//myFunction(): ReferenceError: myFunction is not defined.
```

---

## 9. Message Queue and Event Loop

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i2d5ks32e8an4ww57gyc.gif)

Event loop is a running process that watches call stack & queues. If the call stack is empty, it takes first event in Task queue and pushes it to the call stack.

```
console.log('script start');

setTimeout(function () {
  console.log('setTimeout');
}, 0);

Promise.resolve()
  .then(function () {
    console.log('promise1');
  })
  .then(function () {
    console.log('promise2');
  });

console.log('script end'); 
// script start - promise1 - promise2 - setTimeout - script end
```
---

## 10. setTimeout, setInterval and requestAnimationFrame
<u>1. setTimeout</u>
The setTimeout() method is used to call a function or evaluate an expression after a specified number of milliseconds. For example, let's log a message after 2 seconds using setTimeout method,

```
setTimeout(function () {
  console.log("Good morning");
}, 2000);
```

<u>2. setInterval</u>
The setInterval() method is used to call a function or evaluate an expression at specified intervals (in milliseconds). For example, let's log a message after 2 seconds using setInterval method,

```
setInterval(function () {
  console.log("Good morning");
}, 2000);
```

<u>3. requestAnimationFrame</u>
The question is most simply answered with. requestAnimationFrame produces higher quality animation completely eliminating flicker and shear that can happen when using setTimeout or setInterval, and reduce or completely remove frame skips.

---

## 11. this, call, apply and bind

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wyhxth8lnugsynrrzudn.png)

1. this
['this' keyword](https://www.w3schools.com/js/js_this.asp)

2. Call: The call() method invokes a function with a given this value and arguments provided one by one

```
var employee1 = { firstName: "John", lastName: "Rodson" };
var employee2 = { firstName: "Jimmy", lastName: "Baily" };

function invite(greeting1, greeting2) {
  console.log(
    greeting1 + " " + this.firstName + " " + this.lastName + ", " + greeting2
  );
}

invite.call(employee1, "Hello", "How are you?"); // Hello John Rodson, How are you?
invite.call(employee2, "Hello", "How are you?"); // Hello Jimmy Baily, How are you?
```
3. Apply: Invokes the function with a given this value and allows you to pass in arguments as an array

```
var employee1 = { firstName: "John", lastName: "Rodson" };
var employee2 = { firstName: "Jimmy", lastName: "Baily" };

function invite(greeting1, greeting2) {
  console.log(
    greeting1 + " " + this.firstName + " " + this.lastName + ", " + greeting2
  );
}

invite.apply(employee1, ["Hello", "How are you?"]); // Hello John Rodson, How are you?
invite.apply(employee2, ["Hello", "How are you?"]); // Hello Jimmy Baily, How are you?
```
4. bind: returns a new function, allowing you to pass any number of arguments

```
var employee1 = { firstName: "John", lastName: "Rodson" };
var employee2 = { firstName: "Jimmy", lastName: "Baily" };

function invite(greeting1, greeting2) {
  console.log(
    greeting1 + " " + this.firstName + " " + this.lastName + ", " + greeting2
  );
}

var inviteEmployee1 = invite.bind(employee1);
var inviteEmployee2 = invite.bind(employee2);
inviteEmployee1("Hello", "How are you?"); // Hello John Rodson, How are you?
inviteEmployee2("Hello", "How are you?"); // Hello Jimmy Baily, How are you?
```
Call and apply are pretty interchangeable. Both execute the current function immediately. You need to decide whether it’s easier to send in an array or a comma separated list of arguments. You can remember by treating Call is for comma (separated list) and Apply is for Array.

Whereas Bind creates a new function that will have this set to the first parameter passed to bind().

---

## 12. Objects creation in JavaScript
There are many ways to create objects in javascript as below

Object constructor:

The simplest way to create an empty object is using the Object constructor. Currently this approach is not recommended.

```
var object = new Object();
```
Object's create method:

The create method of Object creates a new object by passing the prototype object as a parameter

```
var object = Object.create(null);
```
Object literal syntax:

The object literal syntax (or object initializer), is a comma-separated set of name-value pairs wrapped in curly braces.

```
var object = {
     name: "Sudheer",
     age: 34
};

```
Object literal property values can be of any data type, including array, function, and nested object.
Note: This is an easiest way to create an object

Function constructor:

Create any function and apply the new operator to create object instances,

```
function Person(name) {
  this.name = name;
  this.age = 21;
}
var object = new Person("Sudheer");
```
Function constructor with prototype:

This is similar to function constructor but it uses prototype for their properties and methods,

```
function Person() {}
Person.prototype.name = "Sudheer";
var object = new Person();
```
This is equivalent to an instance created with an object create method with a function prototype and then call that function with an instance and parameters as arguments.

```
function func() {};

new func(x, y, z);
(OR)

// Create a new instance using function prototype.
var newInstance = Object.create(func.prototype)

// Call the function
var result = func.call(newInstance, x, y, z),

// If the result is a non-null object then use it otherwise just use the new instance.
console.log(result && typeof result === 'object' ? result : newInstance);
```
ES6 Class syntax:

ES6 introduces class feature to create the objects

```
class Person {
  constructor(name) {
    this.name = name;
  }
}

var object = new Person("Sudheer");
```

Singleton pattern:

A Singleton is an object which can only be instantiated one time. Repeated calls to its constructor return the same instance and this way one can ensure that they don't accidentally create multiple instances.

```
var object = new (function () {
  this.name = "Sudheer";
})();
```
---

## 12.Prototype Inheritance and Prototype Chain
Prototype chaining is used to build new types of objects based on existing ones. It is similar to inheritance in a class based language.
[js_object_prototypes](https://www.w3schools.com/js/js_object_prototypes.asp)

---

## 13. Object.create and Object.assign
The **`Object.create()`** method is used to create a new object with the specified prototype object and properties. i.e, It uses an existing object as the prototype of the newly created object. It returns a new object with the specified prototype object and properties.

```
const user = {
  name: "John",
  printInfo: function () {
    console.log(`My name is ${this.name}.`);
  },
};

const admin = Object.create(user);

admin.name = "Nick"; // Remember that "name" is a property set on "admin" but not on "user" object

admin.printInfo(); // My name is Nick

```

You can use the **`Object.assign()`** method which is used to copy the values and properties from one or more source objects to a target object. It returns the target object which has properties and values copied from the target object. The syntax would be as below,

Object.assign(target, ...sources);
Let's take example with one source and one target object,

```
const target = { a: 1, b: 2 };
const source = { b: 3, c: 4 };

const returnedTarget = Object.assign(target, source);

console.log(target); // { a: 1, b: 3, c: 4 }

console.log(returnedTarget); // { a: 1, b: 3, c: 4 }
```
As observed in the above code, there is a common property(b) from source to target so it's value has been overwritten.
Below are the some of main applications of Object.assign() method,

1. It is used for cloning an object.
2. It is used to merge objects with the same properties.

---

## 13. Array functions(map, reduce, filter etc.)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wd82za1lqvac7r8bczat.png)
[Essential-Array-Functions](https://reactdevstation.github.io/2020/03/19/essential-array-functions.html)

## 14. Closures

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/32trrl5bs67xnocbxywe.png)
**Intro**
Closure is a function inside another function that has access to outer function variables

Example 👇

```
function foo() {
     let cat= '🐈'
     function bar() {
          console.log(cat, ' is a cat!')
     }
     bar()
}
foo()
```
**Explanation**
In the above code, foo() created a local variable called cat and a function named bar(). The bar() function is an inner function that is defined inside foo().

Note that bar() don't have it's own variables. However, since inner function have access to variables of outer functions, bar() can access the variable cat.

**Reason**
Why do we learn it❓
Answer ➡️ These are used when one wants to extend the behavior such as pass variables, methods, etc. from an outer function to the inner function.😎

JavaScript is not a pure Object-Oriented Programming language, but you can achieve most of the OOP based behavior through closures.

**Another Example:**
A closure is the combination of a function and the lexical environment within which that function was declared. i.e, It is an inner function that has access to the outer or enclosing function’s variables. The closure has three scope chains

Own scope where variables defined between its curly brackets
Outer function’s variables
Global variables
Let's take an example of closure concept,

```
function Welcome(name) {
  var greetingInfo = function (message) {
    console.log(message + " " + name);
  };
  return greetingInfo;
}
var myFunction = Welcome("John");
myFunction("Welcome "); //Output: Welcome John
myFunction("Hello Mr."); //output: Hello Mr.John
```
As per the above code, the inner function(i.e, greetingInfo) has access to the variables in the outer function scope(i.e, Welcome) even after the outer function has returned.

---

## 15. Functions
**What are lambda or arrow functions**
An arrow function is a shorter syntax for a function expression and does not have its own this, arguments, super, or new.target. These functions are best suited for non-method functions, and they cannot be used as constructors.


**What is a first class function**
In Javascript, functions are first class objects. First-class functions means when functions in that language are treated like any other variable.

For example, in such a language, a function can be passed as an argument to other functions, can be returned by another function and can be assigned as a value to a variable. For example, in the below example, handler functions assigned to a listener

```
const handler = () => console.log("This is a click handler function");
document.addEventListener("click", handler);
```

**What is a first order function**
First-order function is a function that doesn’t accept another function as an argument and doesn’t return a function as its return value.

```
const firstOrder = () => console.log("I am a first order function!");
```

**What is a higher order function**
Higher-order function is a function that accepts another function as an argument or returns a function as a return value or both.

```
const firstOrderFunc = () =>
  console.log("Hello, I am a First order function");
const higherOrder = (ReturnFirstOrderFunc) => ReturnFirstOrderFunc();
higherOrder(firstOrderFunc);
```

**What is a unary function**
Unary function (i.e. monadic) is a function that accepts exactly one argument. It stands for a single argument accepted by a function.

Let us take an example of unary function,

```
const unaryFunction = (a) => console.log(a + 10); // Add 10 to the given argument and display the value
```

**What is the currying function**
Currying is the process of taking a function with multiple arguments and turning it into a sequence of functions each with only a single argument. Currying is named after a mathematician Haskell Curry. By applying currying, a n-ary function turns it into a unary function.

Let's take an example of n-ary function and how it turns into a currying function,

```
const multiArgFunction = (a, b, c) => a + b + c;
console.log(multiArgFunction(1, 2, 3)); // 6

const curryUnaryFunction = (a) => (b) => (c) => a + b + c;
curryUnaryFunction(1); // returns a function: b => c =>  1 + b + c
curryUnaryFunction(1)(2); // returns a function: c => 3 + c
curryUnaryFunction(1)(2)(3); // returns the number 6
Curried functions are great to improve code reusability and functional composition.
```

**What is a pure function**
A Pure function is a function where the return value is only determined by its arguments without any side effects. i.e, If you call a function with the same arguments 'n' number of times and 'n' number of places in the application then it will always return the same value.

Let's take an example to see the difference between pure and impure functions,

```
//Impure
let numberArray = [];
const impureAddNumber = (number) => numberArray.push(number);
//Pure
const pureAddNumber = (number) => (argNumberArray) =>
  argNumberArray.concat([number]);

//Display the results
console.log(impureAddNumber(6)); // returns 1
console.log(numberArray); // returns [6]
console.log(pureAddNumber(7)(numberArray)); // returns [6, 7]
console.log(numberArray); // returns [6]
```
As per the above code snippets, the Push function is impure itself by altering the array and returning a push number index independent of the parameter value. . Whereas Concat on the other hand takes the array and concatenates it with the other array producing a whole new array without side effects. Also, the return value is a concatenation of the previous array.

Remember that Pure functions are important as they simplify unit testing without any side effects and no need for dependency injection. They also avoid tight coupling and make it harder to break your application by not having any side effects. These principles are coming together with Immutability concept of ES6 by giving preference to const over let usage.

**What is a callback function**
A callback function is a function passed into another function as an argument. This function is invoked inside the outer function to complete an action. Let's take a simple example of how to use callback function

```
function callbackFunction(name) {
  console.log("Hello " + name);
}

function outerFunction(callback) {
  let name = prompt("Please enter your name.");
  callback(name);
}

outerFunction(callbackFunction);

```
**Why do we need callbacks**
The callbacks are needed because javascript is an event driven language. That means instead of waiting for a response javascript will keep executing while listening for other events. Let's take an example with the first function invoking an API call(simulated by setTimeout) and the next function which logs the message.

```
function firstFunction() {
  // Simulate a code delay
  setTimeout(function () {
    console.log("First function called");
  }, 1000);
}
function secondFunction() {
  console.log("Second function called");
}
firstFunction();
secondFunction();

Output;
// Second function called
// First function called
```
As observed from the output, javascript didn't wait for the response of the first function and the remaining code block got executed. So callbacks are used in a way to make sure that certain code doesn’t execute until the other code finishes execution.
---

## 16. var, let, const

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jgcjvl8m1xdvo511qjmg.png)

---

## 17. Promises

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/amns0sul00gcw5c00hbl.png)

A promise is an object that may produce a single value some time in the future with either a resolved value or a reason that it’s not resolved(for example, network error). It will be in one of the 3 possible states: fulfilled, rejected, or pending.

The syntax of Promise creation looks like below,

```
const promise = new Promise(function (resolve, reject) {
  // promise description
});
The usage of a promise would be as below,

const promise = new Promise(
  (resolve) => {
    setTimeout(() => {
      resolve("I'm a Promise!");
    }, 5000);
  },
  (reject) => {}
);

promise.then((value) => console.log(value))
```
**Why do you need a promise**
Promises are used to handle asynchronous operations. They provide an alternative approach for callbacks by reducing the callback hell and writing the cleaner code.


**What are the three states of promise**
Promises have three states:

Pending: This is an initial state of the Promise before an operation begins
Fulfilled: This state indicates that the specified operation was completed.
Rejected: This state indicates that the operation did not complete. In this case an error value will be thrown.

**What are the different ways to deal with Asynchronous Code**
Below are the list of different ways to deal with Asynchronous code.

> 1. Callbacks
> 2. Promises
> 3. Async/await
> 4. Third-party libraries such as async.js,bluebird etc



*
*
*
*
*
*
*

> _🎊THIS POST IS UNDER DEVELOPMENT. MANY MORE TOPICS TO COME🎉_