Namaste Javascript484 Notes
Namaste Javascript484 Notes
Execution Context
Everything in JS happens inside the execution context. Imagine a sealed-off container inside which JS
runs. It is an abstract concept that hold info about the env. within the current code is being executed.
In the container the first component is memory component and the 2nd one is code component
Memory component has all the variables and functions in key value pairs. It is also called Variable
environment.
Code component is the place where code is executed one line at a time. It is also called
the Thread of Execution.
Let's consider the below example and its code execution steps:
The very first thing which JS does is memory creation phase, so it goes to line one of above code
snippet, and allocates a memory space for variable 'n' and then goes to line two, and allocates a
memory space for function 'square'. When allocating memory for n it stores 'undefined', a special
value for 'n'. For 'square', it stores the whole code of the function inside its memory space. Then,
as square2 and square4 are variables as well, it allocates memory and stores 'undefined' for them, and
this is the end of first phase i.e. memory creation phase.
Now, in 2nd phase i.e. code execution phase, it starts going through the whole code line by line. As it
encounters var n = 2, it assigns 2 to 'n'. Until now, the value of 'n' was undefined. For function, there is
nothing to execute. As these lines were already dealt with in memory creation phase.
Coming to line 6 i.e. var square2 = square(n), here functions are a bit different than any other
language. A new execution context is created altogether. Again in this new execution context, in
memory creation phase, we allocate memory to num and ans the two variables. And undefined is
placed in them. Now, in code execution phase of this execution context, first 2 is assigned to num.
Then var ans = num * num will store 4 in ans. After that, return ans returns the control of program
back to where this function was invoked from.
When return keyword is encountered, It returns the control to the called line and also the function
execution context is deleted. Same thing will be repeated for square4 and then after that is finished,
the global execution context will be destroyed. So the final diagram before deletion would look
something like:
Javascript manages code execution context creation and deletion with the the help of Call Stack.
Call Stack is a mechanism to keep track of its place in script that calls multiple function.
Call Stack maintains the order of execution of execution contexts. It is also known as Program
Stack, Control Stack, Runtime stack, Machine Stack, Execution context stack.
It should have been an outright error in many other languages, as it is not possible to even access
something which is not even created (defined) yet But in JS, We know that in memory creation
phase it assigns undefined and puts the content of function to function's memory. And in
execution, it then executes whatever is asked. Here, as execution goes line by line and not after
compiling, it could only print undefined and nothing else. This phenomenon, is not an error.
However, if we remove var x = 7; then it gives error. Uncaught ReferenceError: x is not defined
Hoisting is a concept which enables us to extract values of variables and functions even before
initialising/assigning value without getting error and this is happening due to the 1st phase
(memory creation phase) of the Execution Context.
So in previous lecture, we learnt that execution context gets created in two phase, so even before
code execution, memory is created so in case of variable, it will be initialized as undefined while in
case of function the whole function code is placed in the memory. Example:
Outputs:
10
100
1
Code Flow in terms of Execution Context
The Global Execution Context (GEC) is created (the big box with Memory and Code subparts).
Also GEC is pushed into Call Stack
In first phase of GEC (memory phase), variable x:undefined and a and b have their entire
function code as value initialized
In second phase of GEC (execution phase), when the function is called, a new local Execution
Context is created. After x = 1 assigned to GEC x, a() is called. So local EC for a is made inside
code part of GEC.
For local EC, a totally different x variable assigned undefined(x inside a()) in phase 1 , and in
phase 2 it is assigned 10 and printed in console log. After printing, no more commands to run,
so a() local EC is removed from both GEC and from Call stack
Call Stack :[GEC, b()] -> GEC (after printing yet another totally different x value as 100 in console log)
Finally GEC is deleted and also removed from call stack. Program ends.
5 : Shortest JS Program, window & this keyword
The shortest JS program is empty file. Because even then, JS engine does a lot of things. As
always, even in this case, it creates the GEC which has memory space and the execution
context.
JS engine creates something known as 'window'. It is an object, which is created in the global
space. It contains lots of functions and variables. These functions and variables can be
accessed from anywhere in the program. JS engine also creates a this keyword, which points
to the window object at the global level. So, in summary, along with GEC, a global object
(window) and a this variable are created.
In different engines, the name of global object changes. Window in browsers, but in nodeJS it
is called something else. At global level, this === window
If we create any variable in the global scope, then the variables get attached to the global
object.
eg:
In first phase (memory allocation) JS assigns each variable a placeholder called undefined.
undefined is when memory is allocated for the variable, but no value is assigned yet.
When variable is declared but not assigned value, its current value is undefined. But when
the variable itself is not declared but called in code, then it is not defined.
JS is a loosely typed / weakly typed language. It doesn't attach variables to any datatype.
We can say var a = 5, and then change the value to boolean a = true or string a = 'hello' later
on.
Never assign undefined to a variable manually. Let it happen on its own accord.
7 : The Scope Chain, Scope & Lexical Environment
In case 2: 10 is printed. It means that within nested function too, the global scope variable can
be accessed.
In case 3: 100 is printed meaning local variable of the same name took precedence over a
global variable.
In case 4: A function can access a global variable, but the global execution context can't
access any local variable.
So, Lexical Environment = local memory + lexical env of its parent. Hence, Lexical
Environement is the local memory along with the lexical environment of its parent
Lexical: In hierarchy, In order
Whenever an Execution Context is created, a Lexical environment(LE) is also created and is
referenced in the local Execution Context(in memory space).
The process of going one by one to parent and checking for values is called scope chain or
Lexcial environment chain.
8 : let & const in JS, Temporal Dead Zone
Temporal Dead Zone : Time since when the let variable was hoisted until it is initialized some
value.
o So any line till before "let a = 10" is the TDZ for a
o Since a is not accessible on global, its not accessible in window/this also. window.b or
this.b -> 15; But window.a or this.a ->undefined, just like window.x->undefined (x
isn't declared anywhere)
Reference Error are thrown when variables are in temporal dead zone.
Syntax Error doesn't even let us run single line of code.
What is a Block?
Block aka compound statement is used to group JS statements together into 1 group. We
group them within {...}
Reason?
o In the BLOCK SCOPE; we get b and c inside it initialized as undefined as a part of hoisting (in a
seperate memory space called block)
o While, a is stored inside a GLOBAL scope.
o Thus we say, let and const are BLOCK SCOPED. They are stored in a separate mem space which
is reserved for this block. Also, they can't be accessed outside this block. But var a can be
accessed anywhere as it is in global scope. Thus, we can't access them outside the Block.
What is Shadowing?
In console, only b and c are in block space. a initially is in global space(a = 100), and when a = 10 line
is run, a is not created in block space, but replaces 100 with 10 in global space itself.
So, If one has same named variable outside the block, the variable inside the
block shadows the outside variable. This happens only for var
Let's observe the behaviour in case of let and const and understand it's reason.
Both b's are in separate spaces (one in Block(20) and one in Script(another arbitrary mem space)(100)).
Same is also true for *const* declarations.
10 : Closures in JS
Advantages of Closure: Certainly! Let's explore examples for each of the advantages you've
mentioned:
Currying is a technique where a function that takes multiple arguments is transformed into a
series of functions that take one argument each. It enables partial function application and
enhances code flexibility.
Example: Let's create a curried function to calculate the total price of items with tax.
Memoization:
Memoization optimizes expensive function calls by caching their results. It's useful for
recursive or repetitive computations.
Example: Implement a memoized Fibonacci function.
Encapsulation hides the internal details of an object and exposes only necessary methods and
properties. It improves code maintainability and security.
Example: Create a Person class with private properties.
setTimeouts:
setTimeout allows scheduling a function to run after a specified delay. It's commonly used for
asynchronous tasks, animations, and event handling.
Example: Delayed message display.
Disadvantages of Closure:
o Over consumption of memory
o Memory Leak
o Freeze browser
o We expect JS to wait 3 sec, print 1 and then go down and print the string. But JS
prints string immediately, waits 3 sec and then prints 1.
o The function inside setTimeout forms a closure (remembers reference to i). So
wherever function goes it carries this ref along with it.
o setTimeout takes this callback function & attaches timer of 3000ms and stores it.
Goes to next line without waiting and prints string.
o After 3000ms runs out, JS takes function, puts it into call stack and runs it.
Q: Print 1 after 1 sec, 2 after 2 sec till 5 : Tricky interview question
Ans: Overconsumption of memory when using closure as everytime as those closed over
variables are not garbage collected till program expires. So when creating many closures,
more memory is accumulated and this can create memory leaks if not handled.
Garbage collector : Program in JS engine or browser that frees up unused memory. In
highlevel languages like C++ or JAVA, garbage collection is left to the programmer, but in JS
engine its done implicitly.
// Once a() is called, its element x should be garbage collected ideally. But fun b has closure over var x.
So mem of x cannot be freed. Like this if more closures formed, it becomes an issue. To tacke this, JS
engines like v8 and Chrome have smart garbage collection mechanisms. Say we have var x = 0, z = 10
in above code. When console log happens, x is printed as 0 but z is removed automatically.
Q8: Discuss more on Data hiding and encapsulation?
// Why? During mem creation phase a is created in memory and function assigned to a. But b is
created like a variable (b:undefined) and until code reaches the function() part, it is still undefined. So
it cannot be called.
They don't have their own identity. So an anonymous function without code inside it results in
an error.
Anonymous functions are used when functions are used as values eg. the code sample
for function expression above.
Q: Parameters vs Arguments?
We can pass functions inside a function as arguments and /or return a function(HOF). These ability are
altogether known as First class function. It is programming concept available in some other languages
too.
Callback Functions
Functions are first class citizens ie. take a function A and pass it to another function B. Here, A
is a callback function. So basically I am giving access to function B to call function A. This
callback function gives us the access to whole Asynchronous world in Synchronous world.
JS is a synchronous and single threaded language. But due to callbacks, we can do async
things in JS.
In the call stack, first x and y are present. After code execution, they go away and stack is
empty. Then after 5 seconds (from beginning) anonymous suddenly appear up in stack ie.
setTimeout
All 3 functions are executed through call stack. If any operation blocks the call stack, its called
blocking the main thread.
Say if x() takes 30 sec to run, then JS has to wait for it to finish as it has only 1 call stack/1
main thread. Never block main thread.
Always use async for functions that take time eg. setTimeout
Event Listener
// index.html
<button id="clickMe">Click Me!</button>
// in index.js
document.getElementById("clickMe").addEventListener("click", function xyz()
{
//when event click occurs, this callback function (xyz) is called into callstack
console.log("Button clicked");
});
Garbage Collection and removeEventListeners
Event listeners are heavy as they form closures. So even when call stack is empty,
EventListener won't free up memory allocated to count as it doesn't know when it may need
count again. So we remove event listeners when we don't need them (garbage collected)
onClick, onHover, onScroll all in a page can slow it down heavily.
Browser has JS Engine which has Call Stack which has Global execu on context, local
execu on context etc.
o But browser has many other superpowers - Local storage space, Timer, place to enter
URL, Bluetooth access, Geoloca on access and so on.
o Now JS needs some way to connect the callstack with all these superpowers. This is
done using Web APIs.
WebAPIs
None of the below are part of Javascript! These are extra superpowers that browser has. Browser
gives access to JS callstack to use these powers.
setTimeout(), DOM APIs, fetch(), localstorage, console (yes, even console.log is not JS!!),
loca on and so many more.
o DOM APIs : eg.Document.xxxx ; Used to access HTML DOM tree. (Document Object
Manipula on)
o fetch() : Used to make connec on with external servers eg. Ne lix servers etc.
We get all these inside call stack through global object ie. window
o As window is global obj, and all the above func ons are present in global object, we
don't explicity write window but it is implied.
Let's undertand the below code image and its
explaina on:
o First a GEC is created and put inside call stack.
o console.log("Start"); // this calls the console web api (through window) which in turn
actually modifies values in console.
o setTimeout(func on cb() { //this calls the setTimeout web api which gives access to
mer feature. It stores the callback cb() and starts mer. console.log("Callback");},
5000);
o console.log("End"); // calls console api and logs in console window. A er this GEC
pops from call stack.
o While all this is happening, the mer is constantly cking. A er it becomes 0, the
callback cb() has to run.
o Now we need this cb to go into call stack. Only then will it be executed. For this we
need event loop and Callback queue
cb() cannot simply directly go to callstack to be execeuted. It goes through the callback
queue when mer expires.
Event loop keep checking the callback queue, and see if it has any element to puts it into call
stack. It is like a gate keeper.
Once cb() is in callback queue, eventloop pushes it to callstack to run. Console API is used
and log printed
Q: Another example to understand Eventloop & Callback Queue.
See the below Image and code and try to understand the reason
Explana on?
// cb() registered inside webapi environment and event(click) a ached to it. i.e. REGISTERING CALLBACK AND
ATTACHING EVENT TO IT.
// In above code, even a er console prints "Start" and "End" and pops GEC out, the eventListener stays in
webapi env(with hope that user may click it some day) un l explicitly removed, or the browser is closed.
Ans: Suppose user clciks bu on x6 mes. So 6 cb() are put inside callback queue. Event loop sees if call stack is
empty/has space and whether callback queue is not empty(6 elements here). Elements of callback queue
popped off, put in callstack, executed and then popped off from call stack.
Code Explaina on:
* Same steps for everything before fetch() in above code.
* fetch registers cbF into webapi environment along with exis ng cbT.
* cbT is wai ng for 5000ms to end so that it can be put inside callback queue. cbF is wai ng for data to be returned from Ne lix servers
gonna take 2 seconds.
* A er this millions of lines of code is running, by the me millions line of code will execute, 5 seconds has finished and now the mer has
expired and response from Ne lix server is ready.
* Data back from cbF ready to be executed gets stored into something called a Microtask Queue.
* Microtask Queue is exactly same as Callback Queue, but it has higher priority. Func ons in Microtask Queue are executed earlier than
Callback Queue.
* In console, first Start and End are printed in console. First cbF goes in callstack and "CB Ne lix" is printed. cbF popped from callstack.
Next cbT is removed from callback Queue, put in Call Stack, "CB Timeout" is printed, and cbT removed from callstack.
All the callback func ons that come through promises go in microtask Queue.
Muta on Observer : Keeps on checking whether there is muta on in DOM tree or not, and if
there, then it execeutes some callback func on.
Callback func ons that come through promises and muta on observer go inside Microtask
Queue.
All the rest goes inside Callback Queue aka. Task Queue.
If the task in microtask Queue keeps crea ng new tasks in the queue, element in callback
queue never gets chance to be run. This is called starva on.
1. When does the event loop actually start ? - Event loop, as the name suggests, is a single-
thread, loop that is almost infinite. It's always running and doing its job.
2. Are only asynchronous web api callbacks are registered in web api environment? - YES, the
synchronous callback func ons like what we pass inside map, filter and reduce aren't
registered in the Web API environment. It's just those async callback func ons which go
through all this.
3. Does the web API environment stores only the callback func on and pushes the same
callback to queue/microtask queue? - Yes, the callback func ons are stored, and a reference
is scheduled in the queues. Moreover, in the case of event listeners(for example click
handlers), the original callbacks stay in the web API environment forever, that's why it's
adviced to explicitly remove the listeners when not in use so that the garbage collector does
its job.
4. How does it ma er if we delay for setTimeout would be 0ms. Then callback will move to
queue without any wait ? - No, there are trust issues with setTimeout() . The callback
func on needs to wait un l the Call Stack is empty. So the 0 ms callback might have to wait
for 100ms also if the stack is busy.
JRE is like a big container which has everything which are required to run Javascript code.
JRE consists of a JS Engine ( of JRE), set of APIs to connect with outside environment,
event loop, Callback queue, Microtask queue etc.
Browser can execute javascript code because it has the Javascript Run me Environment.
ECMAScript is a governing body of JS. It has set of rules which are followed by all JS engines
like Chakra(Edge), Spidermonkey(Firefox)(first javascript engine created by JS creator
himself), v8(Chrome)
Javascript Engine is not a machine. Its so ware wri en in low level languages (eg. C++) that
takes in hi-level code in JS and spits out low level machine code.
Code inside Javascript Engine passes through 3 steps : Parsing, Compila on and Execu on
i. Parsing - Code is broken down into tokens. In "let a = 7" -> let, a, =, 7 are all tokens.
Also we have a syntax parser that takes code and converts it into an AST (Abstract
Syntax Tree) which is a JSON with all key values like type, start, end, body etc (looks
like package.json but for a line of code in JS. Kinda unimportant)(Check out
astexplorer.net -> converts line of code into AST).
ii. Compila on - JS has something called Just-in- me(JIT) Compila on - uses both
interpreter & compiler. Also compila on and execu on both go hand in hand. The
AST from previous step goes to interpreter which converts hi-level code to byte code
and moves to execeu on. While interpre ng, compiler also works hand in hand to
compile and form op mized code during run me. Does JavaScript really
Compiles? The answer is a loud YES. JS used to be only interpreter in old mes, but
now has both to compile and interpreter code and this make JS a JIT compiled
language, its like best of both world.
iii. Execu on - Needs 2 components ie. Memory heap(place where all memory is
stored) and Call Stack(same call stack from prev episodes). There is also a garbage
collector. It uses an algo called Mark and Sweep.
17 : Trust issues with setTimeout()
setTimeout with mer of 5 secs some mes does not exactly guarantees that the callback
func on will execute exactly a er 5s.
// o/p: Over here setTimeout exactly doesn't guarantee that the callback func on will be called
exactly a er 5s. Maybe 6,7 or even 10! It all depends on callstack. Why?
Reason?
o When setTimeout is seen, callback func on is registered into webapi's env. And
mer is a ached to it and started. callback waits for its turn to be execeuted once
mer expires. But JS waits for none. Goes to next line.
o A er "End", we have 1 million lines of code that takes 10 sec(say) to finish execu on.
So GEC won't pop out of stack. It runs all the code for 10 sec.
o But in the background, the mer runs for 5s. While callstack runs the 1M line of
code, this mer has already expired and callback fun has been pushed to Callback
queue and wai ng to pushed to callstack to get executed.
o Event loop keeps checking if callstack is empty or not. But here GEC is s ll in stack so
cb can't be popped from callback Queue and pushed to CallStack. Though
setTimeout is only for 5s, it waits for 10s un l callstack is empty before it can
execute (When GEC popped a er 10sec, callstack() is pushed into call stack and
immediately executed (Whatever is pushed to callstack is executed instantly).
o This is called as the Concurrency model of JS. This is the logic behind setTimeout's
trust issues.
The First rule of JavaScript: Do not block the main thread (as JS is a single threaded(only 1
callstack) language).
In below example, we are blocking the main thread. Observe Ques ons and Output.
setTimeout guarantees that it will take at least the given mer to execute the code.
JS is a synchronous single threaded language. With just 1 thread it runs all pieces of code. It
becomes kind of an interpreter language, and runs code very fast inside browser (no need to
wait for code to be compiled) (JIT - Just in me compila on). And there are s ll ways to do
async opera ons as well.
// Even though mer = 0s, the cb() has to go through the queue. Registers calback in
webapi's env , moves to callback queue, and execute once callstack is empty.
// This method of pu ng mer = 0, can be used to defer a less imp func on by a li le so the
more important func on(here prin ng "End") can take place
Map func on
It is basically used to transform a array. The map() method creates a new array with the results of
calling a func on for every array element.
const output = arr.map(func on) // this func on tells map that what transforma on I want on each
element of array
//In above example sum was ini alized with 0, so over here accumulator also needs to be ini alized,
so the second argument to reduce func on represent the ini aliza on value.
20 : Callback
JavaScript is synchronous, single threaded language. It can Just do one thing at a time, it has just
one call-stack and it can execute one thing at a time. Whatever code we give to Javascript will be
quickly executed by Javascript engine, it does not wait.
// Over here `createOrder` api is first crea ng a order then it is responsible to call
`api.proceedToPayment()` as part of callback approach.
When we have a large codebase and mul ple apis and have dependency on each other, then we fall
into callback hell. These codes are tough to maintain. These callback hell structure is also known
as Pyramid of Doom.
Till this point we are comfortable with concept of callback hell but now lets discuss about Inversion
of Control. It is very important to understand in order to get comfortable around the concept of
promise.
Inversion of control is like that you lose the control of code when we are using callback.
// So over here, we are crea ng a order and then we are blindly trus ng `createOrder` to call
`proceedToPayment`.
// When we pass a func on as a callback, basically we are dependant on our parent func on that
it is his responsibility to run that func on. This is called `inversion of control` because we are
dependant on that func on. What if parent func on stopped working, what if it was developed by
another programmer or callback runs two mes or never run at all.
/**
* When above line is executed, `fetch` makes API call and return a
`promise` instantly which is in `Pending` state and Javascript doesn't wait
to get it `fulfilled`
* And in next line it console out the `pending promise`.
* NOTE: chrome browser has some in-consistency, the moment console happens
it shows in pending state but if you will expand that it will show
fulfilled because chrome updated the log when promise get fulfilled.
* Once fulfilled data is there in promiseResult and it is inside body in
ReadableStream format and there is a way to extract data.
*/
Interview Guide
What is Promise?
-> Promise object is a placeholder for certain period of me un l we receive value from
asynchronous opera on.
We are now done solving one issue of callback i.e. Inversion of Control
Q: What is async?
A: Async is a keyword that is used before a function to create a async function.
await function() {} // Syntax error: await is only valid under async function.
}, 3000);
})
// 📌 Promise.then/.catch way
function getData() {
console.log('Hello There!');
//❓ Problem: Normally one used to get confused that JS will wait
for promise to be resolved before executing following lines.
// 📌 async-wait way:
console.log('Hello There!');
console.log(val);
console.log('Hi');
console.log('Hello There!');
console.log(val);
console.log(val2);
}
handlePromise();
// In above code example, will our program wait for 2 time or will
it execute parallely.
//📌 `Hi` printed instantly -> now code will wait for 3 secs ->
After 3 secs both promises will be resolved so ('Hello There!'
'Promise resolved value!!' 'Hello There! 2' 'Promise resolved
value!!') will get printed immediately.
// Let's create one promise and then resolve two different promise.
setTimeout(() => {
}, 2000);
})
console.log('Hi');
console.log('Hello There!');
console.log(val);
console.log(val2);
}
handlePromise();
// 📌 `Hi` printed instantly -> now code will wait for 3 secs ->
After 3 secs both promises will be resolved so ('Hello There!'
'Promise resolved value!!' 'Hello There! 2' 'Promise resolved value
by p2!!') will get printed immediately. So even though `p2` was
resolved after 2 secs it had to wait for `p` to get resolved
console.log('Hi');
console.log('Hello There!');
console.log(val);
console.log(val2);
handlePromise();
// 📌 `Hi` printed instantly -> now code will wait for 2 secs ->
After 2 secs ('Hello There!' 'Promise resolved value by p2!!') will
get printed and in the subsequent second i.e. after 3 secs ('Hello
There! 2' 'Promise resolved value!!') will get printed
setTimeout(() => {
}, 5000);
})
setTimeout(() => {
}, 10000);
})
console.log('Hi');
debugger;
console.log('Hello There!');
debugger;
console.log(val);
console.log(val2);
handlePromise();
// call stack flow -> handlePromise() is pushed -> It will log `Hi` to
console -> Next it sees we have await where promise is suppose to be
resolved -> So will it wait for promise to resolve and block call stack? No
-> thus handlePromise() execution get suspended and moved out of call stack
-> So when JS sees await keyword it suspend the execution of function till
promise is resolved -> So `p` will get resolved after 5 secs so
handlePromise() will be pushed to call-stack again after 5 secs. -> But
this time it will start executing from where it had left. -> Now it will
log 'Hello There!' and 'Promise resolved value!!' -> then it will check
whether `p2` is resolved or not -> It will find since `p2` will take 10
secs to resolve so the same above process will repeat -> execution will be
suspended until promise is resolved.
};
handlePromise()
Error Handling
While we were using normal Promise we were using .catch to handle error, now in async-
await we would be using try-catch block to handle error.
try {
console.log(res);
} catch (err) {
console.log(err)
};
handlePromise()
// In above whenever any error will occur the execution will move to catch
block. One could try above with bad url which will result in error.
Promise.all()
Promise.allSettled()
Promise.race()
Promise.any()
💡 One simply doesn't use async/await without knowing promises!
Promise.all()
A promise is a placeholder for a value that's going to be available sometime later. The promise helps handle
asynchronous operations. JavaScript provides a helper function Promise.all(promisesArrayOrIterable) to handle
multiple promises at once, in parallel, and get the results in a single aggregate array.
Q: In what situation one could use above api?
A: Suppose, you have to make parallel API call and get the result, how one can do? This is where Promise.all
can be utilized. It is used to handle multiple promises together.
Promise.all([p1, p2, p3]) -> Lets assume we are making 3 API call to fetch data. Also assume p1 takes 3
seconds, p2 takes 1 second, p3 takes 2 seconds.
In first scenario let's assume all 3 promises are successful. So Promise.all will take 3secs and will give promise
value of result like [val1, val2, val3]. It will wait for all of them to finish then it will collect the results and give array
as output.
What if any of the promise gets rejected, for eg: Promise.all([p1, p2, p3]). But this time, p2 get rejected after 1
sec. Thus Promise.all will throw same error as p2 immediately as soon as error happened. It will not wait for other
promise to either become success or failure. Moreover, p1 and p2 wont get cancelled as they are already
triggered so it may result in success or failure depending upon their fate but Promise.all wont care. So its a
situation of or/null.
💡 To conclude, the Promise.all() waits for all the input promises to resolve and returns a new promise that
resolves to an array containing the results of the input promises. If one of the input promises is rejected, the
Promise.all() method immediately returns a promise that is rejected with an error of the first rejected promise.
Promise.allSettled()
Promise.allSettled() method that accepts a list of Promises and returns a new promise that resolves after all the
input promises have settled, either resolved or rejected.
Promise.allSettled([p1, p2, p3]) -> Lets assume we are making 3 API call to fetch data. Also assume p1 takes 3
seconds, p2 takes 1 second, p3 takes 2 seconds.
In first scenario let's assume all 3 promises are successful. So Promise.allSettled will take 3secs and will give
promise value of result like [val1, val2, val3]. It will wait for all of them to finish then it will collect the results and
give array as output.
What if any of the promise gets rejected, for eg: Promise.all([p1, p2, p3]). But this time, p2 get rejected after 1
sec. Thus Promise.allSettled will still wait for all promises to get settled. So After 3 secs, it will be [val1, err, val3]
Promise.race()
The Promise.race() static method accepts a list of promises as an iterable object and returns a new promise that
fulfills or rejects as soon as there is one promise that fulfills or rejects, with the value or reason from that promise.
The name of Promise.race() implies that all the promises race against each other with a single winner, either
resolved or rejected.
Promise.race([p1, p2, p3]) -> Lets assume we are making 3 API call to fetch data. Also assume p1 takes 3
seconds, p2 takes 1 second, p3 takes 2 seconds. So as soon as first promise will resolve or reject, it will give
the output.
So in Happy scenario, Promise.race will give (val2) as output after 1sec as p2 got resolved at the earliest.
Whereas if it would have been failed Promise.race would have still given output after 1 sec but this time with
error.
Promise.any()
The Promise.any() method accepts a list of Promise objects as an iterable object. If one of the promises in the
iterable object is fulfilled, the Promise.any() returns a single promise that resolves to a value which is the result of
the fulfilled promise.
Promise.any([p1, p2, p3]) -> Lets assume we are making 3 API call to fetch data. Also assume p1 takes 3
seconds, p2 takes 1 second, p3 takes 2 seconds. So as soon as first promise will be successful, it will give the
output.
If in above situation what if p2 got rejected, nothing will happen as Promise.any seek for success, so the moment
first success will happen that will become the result.
❓ But what if all promises got failed, so the returned result will be aggregated error i.e. [err1, err2, err3].
Code Examples:
Promise.all()
// 📌 First Scenario
// 📌 Second Scenario
Promise.allSettled()
💡This is safest among all Promises API.
// Over here, it will wait for all promises to be either settled or rejected and
then return,
/* {status: 'fulfilled', value: 'P1 Success'},
*/
Promise.race()
// 📌 Second Scenario
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {resolve('P1 Success');}, 3000);});
Notes:
Once promise is settled, it means -> got the result. Moreover, settled is broadly divided into two
categories:
Promise.any()
// 📌 First Scenario
// 📌 Third Scenario
Summary
There are 6 static methods of Promise class:
Promise.all(promises) – waits for all promises to resolve and returns an array of their results. If any of the given
promises rejects, it becomes the error of Promise.all, and all other results are ignored.
Promise.allSettled(promises) (recently added method) – waits for all promises to settle and returns their results
as an array of objects with: status: "fulfilled" or "rejected" value (if fulfilled) or reason (if rejected).
Promise.race(promises) – waits for the first promise to settle, and its result/error becomes the outcome.
Promise.any(promises) (recently added method) – waits for the first promise to fulfill, and its result becomes the
outcome. If all of the given promises are rejected, AggregateError becomes the error of Promise.any.
Promise.resolve(value) – makes a resolved promise with the given value.
Promise.reject(error) – makes a rejected promise with the given error. Of all these, Promise.all is probably the
most common in practice.
Episode 25 : this keyword in JavaScript: In JavaScript, the this keyword refers to an object, which object depends on how
function x() {
// the below value depends on strict/non-strict mode
console.log(this);
// in strict mode – undefined
// in non-strict mode - refers to global window object}
x();
// 💡 Notes:
// On the first go feels like `this` keyword in global space and inside function behaves same
but in reality it's different.
// The moment you make JS run in strict mode by using: "use strict" at the top, `this` keyword
inside function returns `undefined` whereas global space will still refers to global window
object
this substitution -> According to this substitution, if the value of this keyword is null/undefined , it will be
replaced by globalObject only in non-strict mode. This is the reason why this refers to global window object inside function in
non-strict mode.
💡 So to summarize, the value of this keyword inside function is undefined , but because of this substitution in
non-strict mode this keyword refers to globalWindowObject and in strict mode it will still be undefined
this keyword value depends on how the function is called. For eg:
In strict mode:
x(); // undefined
window.x(); // global window object
const student = {
name: 'Alok',
printName: function () {
console.log(this.name);}}
student.printName(); // Alok
const student2 = {
name: 'Kajal',
}
student2.printName(); // throw error// ❓ how to re-use printName method from `student`
object
student.printName.call(student2); // Kajal
// Above `call` method is taking the value of `this` keyword
// So, Inside `printName` method value of `this` is now `student2` object// So, call, bind and
apply is used to set the value of this keyword.
Arrow function doesn't have their own this value, they take the value from enclosing lexical context.
const obj = {
a: 10,
x: () => {
console.log(this); // window object // Above the value of `this` won't be obj anymore
instead it will be enclosing lexical context i.e. window object in current scenario.
}}
obj.x();
const obj2 = {
a: 10,
x: function () {
const y = () => {
console.log(this);
// Above the value of `this` will be obj2 as function y's enclosing lexical
context is function `x`.
};
y();
}}
obj2.x();