JavaScript Fundamentals

How JavaScript executes the code?

JavaScript is single-threaded, which means only one statement is executed at a time. As the JS engine processes our script line by line, it uses this single Call-Stack to keep track of codes that are supposed to run in their respective order.

Call Stack: Whenever to run the JavaScript code the JavaScript engine uses a call stack, call stack execute the code.In side the call Stack Global execution content and Function execution content.

Flow of Execution:

Web API : A Web API is an application programming interface (API) for either a web server or a web browser. It is provides the interaction between the server and user.

Callback Queue/ Task Queue : In the execute flow of Js code, web API'S completed the execution then come and sitting into callback/ Task Queue. Task Queue nothing but a get the functions from the Web API and Ready to go on call stack.

Event Loop : JavaScript has a runtime model based on an event loop, which is responsible for executing the code, collecting and processing events, and executing queued callbacks.

SYNCHRONOUS Task :

  • In the Above fig shows how a typical line by line execution happens.

  • Step 1: The console.log("Print 1")is pushed into the call stack and executed, once done with execution, it is then popped out of the stack. Now the stack is empty and ready for any next instruction to be executed.
    Step 2:console.log("Print 2"); // is the next instruction is pushed and the same thing repeats until go the completed that task.

  • Step 3:console.log("Print 3");is executed and there is nothing left to push and execute.

Step 1: Call stack is pushed with the first executable statement of our script the First() function call. While executing through the scope of the function First() our engine encounters another function call Second()

Step 2: Hence the function call Second() is pushed into the call stack and the engine starts executing Second()function’s body (Note: The functionFirst()is still not finished), again, there’s another function call Third() inside Second()'s body.

Step 3: Likewise the function call Third() is pushed into the call stack and the engine starts processing Third() function definition. While the functions Second() and First()still living in the stack waiting for their turn (successor to finish their execution) respectively.

Step 4: So when the engine encounters a return ; statement within the function definition of Third() , well that’s the end of Third() . Hence Third() is popped out of the call stack as it has finished execution. At this point, the engine is back at executing Second() ‘s offerings.

Step 5: Well as the engine encounters a return ; statement, the function Second() is popped out and the engine starts executing First() . Now there’s no return statement within the First() ‘s scope so the engine executes its body until the end of scope and pops First() out of the stack at Step 6.

That’s how a script of synchronous tasks gets handled by our browser without involving anything other than the “legendary” Call Stack. But things get a little bit complex when JS engine encounters an asynchronous task.

ASYNCHRONOUS Task :

Step 1: As usual console.log("Hello ") gets pushed into the stack first and is executed then popped out when done.
Step 2:setTimeout() gets pushed into the stack, but Note- console.log("Siddhartha") cannot be executed (or pushed to the stack) immediately because it is meant to execute in some future time (i.e. after a minimum of 2 seconds). So it disappears for now (will explain later where it disappears to).
Step 3: Naturally next line console.log(" I am ") is pushed into the stack, gets executed, and is popped out immediately.
Step 4: Call stack is empty and waiting.
Step 5: Suddenly console.log( "Siddhartha" ) is found pushed into the stack after 2 seconds as setTimeout() has timed out. It is then executed and once done is popped out of the Stack at Step 6: Stack is empty again.

What is difference between Sync & Async?

Synchronous : In the Synchronous the code executes line by line at a time based upon the instructions. some times some type of code is blocked.

Asynchronous : This opposite to the Synchronous. code not execute the line by line at a time, its take some time. By using this operations we can built the long running Applications.

How can we make sync code into async?

To convert synchronous code into asynchronous code, We need to use asynchronous programming techniques and features . Here main Three types of Apporches :

callback Functions : To handle the Asynchronous operations by using the call back functions.

fetch('https://cat-fact.herokuapp.com/facts')
      .then(response => {
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        return response.text()
      })
      .then(data =>{
        console.log(data)
      })
      .catch(error => {
        console.error('Error fetching data:', error);
      });

Promises : To handle the Asynchronous operations by using the promises.

let promise = new Promise ((resolve, reject) =>{
    setTimeOut(() =>{
      resolve("rama chandra")
  }, 2*1000)
})
promise.then(resolve =>{
   console.log(resolve)
}).catch(err =>{
  console.log(err)
})
const fs = require('fs');

const data = 'console.log("hello world")
const filePath = 'javaScript.txt';
const writeFilePromise = new Promise((resolve, reject) => {
    fs.writeFile(filePath, data, (error) => {
        if (error) {
            reject(error);
        } else {
            resolve(); 
        }
    });
});
writeFilePromise
    .then(() => {
        console.log('Data written to file successfully.');
    })
    .catch((error) => {
        console.error('Error writing to file:', error);
    });

By Using Async & Await :

async function getData(){
        try {
            let a = await _fetch('https://cat-fact.herokuapp.com/facts')
           console.log( await a.text())
        } catch (error) {
            console.log(error)
        }
    }
    getData()

What are callback & what are the drawbacks of using callbacks?

Callback : A callback is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.

There are two ways in which the callback may be called: synchronous and asynchronous. synchronous callbacks are called immediately after the invocation of the outer function, with no intervening asynchronous tasks, while asynchronous callbacks are called at some point later, after an asynchronous operation has completed.

//Asynchronous callback 
let greetings = setTimeout(function() { 
console.log('Hello, Good Morning)
 }, 2000); 
console.log(greetings);
const cricketPlayer = {
    name: 'Sachin Tendulkar',
    country: 'India',
    age: 48,
    totalRuns: 18426,
    centuries: 100,
    retired: true
};

//  by using Object 
function getValues( obj, callback){
  for(const value in obj){
        let value1 = obj[value]
        callback(value1)
      }
}
function resultObj(result) {
    console.log('Result:', result);
}
getValues(cricketplayer, resultObj)

Drawbacks :

  1. Callbacks can lead to nested code, which can be difficult to read and maintain.

  2. By using the Callbacks, loss the control of the code.

  3. Callbacks can make it difficult to debug your code.

How promises solves the problem of inversion of control?

Mainly inversion of controls occurs in the Asynchronous operations. In this operations approaches by using the callbacks and promises.

To handling asynchronous operations often involved the use of callback functions.its gets call back hell.

By using Promises, we can handle the inversion of control problem in asynchronous code by providing a more structured and organised way to deal with asynchronous operations and their results. This helps to make the code more readable and maintainable.

What are different functions in promises? ( You can cover, promise.all, promise.race etc. )

Function : It is a block of code, stored inside the cruel brackets. It should take some input and return an output where there is some obvious relationship between the input and the output.

Promise : Promises in JavaScript help to solve the problem of inversion of control. Promises address this issue by providing a way to handle asynchronous operations in a more structured and organised manner.

promise.resolve() : it is creates the resolve promise.

let promise = Promise.resolve("success")
promise.then( resolve =>{
    console.log(resolve)
})
.catch( err =>{
  console.error(err)
})

promise.reject(): It is creates the reject promise.

let promise = Promise.reject("success")
promise.then( resolve =>{
    console.log(resolve)
})
.catch( err =>{
  console.error(err)
})

promise.all(): It is returns all promise that resolves when the one promise as reject its returns reject.

let promise1 = new Promise((resolve, reject) => {
        reject(1);
      });
      let promise2 = new Promise((resolve, reject) => {
        setTimeout(resolve, 1000,2);
      });
      Promise.all([promise1, promise2]).then( () => {
        console.log("Both the promises have been resolved successfully.");
      }).catch(() =>{
        console.log("rejected")
      });

promise. allsettled(): It is wait for all the promise fulfilled then returns array states of outcomes of the each promises.

let promise1 =  Promise.resolve("rock")
 let promise4 =  Promise.reject(new Error("wrong"))
 let promise2 =  Promise.resolve("rock")
 let promise3 =  Promise.resolve("rock")

 Promise.allSettled([promise1, promise2, promise3, promise4]).then((data)=>{
    data.forEach(element => {
         if(element.status == "fulfilled")
         {
            console.log(element.value)        
           }else{
          console.error(`Promise  was rejected with reason:`, element.reason.message);
         }
    });
 }).catch((err) =>{
   console.log(err)
})

promise.race() : In the set of promises which one is first fulfilled the promise its returns first one only.

const promise1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'one');
  });

  const promise2 = new Promise((resolve, reject) => {
    setTimeout(reject, 200, 'two');
  });

  const promise3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 300, 'three');
  });

  Promise.race([promise1, promise2, promise3])
    .then((value) => {
      console.log(value); // This will print 'one' because promise1 resolves first
    })
    .catch((error) => {
      console.error(error); // This will not be executed since promise1 resolves
    });