Javascript: The Intricate Concepts

February 12, 2024

Thread of execution

JavaScript is a concurrent language that only executes on one thread. All the asynchronous aspects of the language are just simulations managed by the engine.

Call stack, Event loop, Callback queue and Micro-task queue

At the start of the program, a stack structure named the call stack is filled with the global context, meaning all synchronous code line by line. Once a function finishes its execution, it gets popped out of the call stack. Within the global context, there may be calls to asynchronous functions. These functions do not execute in the same way synchronous code does. Instead, they are pushed onto the event loop. The event loop is what decides, based on the priority of the task, whether that task will be pushed to the Callback queue (Low priority) or the micro-task queue (High priority). The moment the call stack is empty, the engine will attempt to empty the micro-task queue and then the callback queue, by pushing async functions of which the execution condition is met, onto the call stack, executing all the code dependent on a promise. This flow of execution is what can we can sometimes notice when using functions like setTimeout and setInterval, which at times do not conform to the intuitive understanding and expectation of time given to them.

Higher order functions

Higher-order functions are functions that can accept functions as arguments and can return functions. They allow things like closures and enable functional programming.

Promises

Promises are a fundamental concept in JavaScript for managing asynchronous operations. They represent a value that may be available now, or in the future, or never. Promises provide a cleaner alternative to callback-based approaches for handling asynchronous operations, allowing for more readable and maintainable code.

Closures

Closures are a powerful feature in JavaScript that allows inner functions to access variables from their outer (enclosing) scope even after the outer function has finished executing. This enables functions to "remember" and maintain state, leading to more flexible and concise code. Closures are commonly used in scenarios such as creating private variables and implementing callbacks.

Async/Await

Async/await is a modern syntax for handling asynchronous operations in JavaScript in a more synchronous-looking manner. It allows developers to write asynchronous code that resembles synchronous code, making it easier to understand and maintain. The async keyword is used to define asynchronous functions, while await is used to pause execution until a promise is resolved or rejected.

Dynamic Imports

Dynamic imports enable loading JavaScript modules dynamically at runtime, rather than statically at compile time. This allows developers to conditionally import modules, lazy-load code, and improve performance by reducing initial bundle sizes. Dynamic imports are particularly useful in large-scale applications and scenarios where modules are only needed under specific conditions.

Modules

Modules in JavaScript provide a way to organize code into reusable units with clear boundaries and encapsulation. ES6 introduced native support for modules, allowing developers to export and import functionalities between different files or modules. Modules promote modularity, maintainability, and code reuse, facilitating the development of complex applications with ease.

Currying

Currying is a functional programming technique where a function with multiple arguments is transformed into a sequence of functions, each taking a single argument. This allows for partial application of arguments, enabling more flexible and reusable code. Currying is commonly used in scenarios such as function composition, creating specialized functions, and improving code readability.