Category: Miscellaneous

  • Atomics Objects

    The Atomics object in JavaScript provides a set of static methods for performing atomic operations on SharedArrayBuffer objects. Atomic operations are operations that are guaranteed to be completed in a single step, without being interrupted by other threads. This makes them useful for implementing concurrent data structures and algorithms.

    The Atomics object in JavaScript, as part of the ECMAScript standard, serves as a crucial tool for managing shared memory in a multi-threaded environment. Let’s understand the basic concept of atomic operations in more detail:

    Atomics Object

    The Atomics object is a built-in JavaScript object that provides atomic operations on shared memory. It is designed to be used in a multi-threaded environment, where multiple threads or Web Workers may be concurrently accessing and modifying shared data.

    The Essence of “Atomic”

    In the context of the Atomics object, “atomic” signifies a crucial characteristic: it performs operations that are inherently indivisible. When we declare an operation as atomic; we imply its execution occurs continuously and uninterruptedly like a single unit. This quality is indispensable in preventing race conditions; these arise when concurrent operations’ outcomes depend on their timing and sequence of execution.

    Atomic Operations

    Atomic operations are low-level operations on shared memory that are guaranteed to be executed as a single, uninterruptible unit. These operations include additions, subtractions, bitwise operations, exchanges, and more.

    The Atomics object provides methods like add, sub, and, or, xor, load, store, exchange, and others, each corresponding to a specific atomic operation.

    Sr.No.Method & Description
    1Atomics.add()Adds a specified value to the element at the specified index in the typed array. Returns the original value atomically.
    2Atomics.sub()Subtracts a specified value from the element at the specified index in the typed array. Returns the original value atomically.
    3Atomics.and()Performs an atomic bitwise AND operation on the element at the specified index in the typed array with the given value. Returns the original value atomically.
    4Atomics.or()Performs an atomic bitwise OR operation on the element at the specified index in the typed array with the given value. Returns the original value atomically.
    5Atomics.xor()Performs an atomic bitwise XOR operation on the element at the specified index in the typed array with the given value. Returns the original value atomically.
    6Atomics.load()Retrieves the value at the specified index in the typed array atomically.
    7Atomics.store()Stores the given value at the specified index in the typed array atomically.
    8Atomics.exchange()Swaps the value at the specified index in the typed array with a specified value. Returns the original value atomically.
    9Atomics. compareExchange()Compares the value at the specified index in the typed array with a provided expected value, and if they match, updates the value with a new value. Returns the original value atomically.
    10Atomics.wait()Atomically waits for a value at the specified index in the typed array to be a specific value and then returns. Allows for efficient coordination between threads.
    11Atomics.notify()Atomically notifies the wait queue associated with the specified index in the typed array.

    Examples

    Example 1: Basic Usage of Atomics Operations

    In this example, the Atomics object is demonstrated for its fundamental atomic operations on shared memory. These operations include addition, subtraction, bitwise AND, OR, XOR, loading, storing, exchanging, and compare-exchanging values. Each operation ensures the indivisibility of the executed unit, crucial for preventing race conditions in a multi-threaded environment.

    Atomics.add()

    // Shared memory setupconst sharedBuffer =newSharedArrayBuffer(4);const sharedArray =newInt32Array(sharedBuffer);// Atomics.add()const originalAddValue = Atomics.add(sharedArray,0,10);
    console.log(Atomics.add: Original value: ${originalAddValue}, New value: ${sharedArray[0]});

    Output

    Atomics.add: Original value: 0, New value: 10
    

    Atomics.add()

    // Shared memory setupconst sharedBuffer =newSharedArrayBuffer(4);const sharedArray =newInt32Array(sharedBuffer);// Atomics.sub()const originalSubValue = Atomics.sub(sharedArray,0,5);
    console.log(Atomics.sub: Original value: ${originalSubValue}, New value: ${sharedArray[0]});

    Output

    Atomics.sub: Original value: 10, New value: 5
    

    Atomics.add()

    // Shared memory setupconst sharedBuffer =newSharedArrayBuffer(4);const sharedArray =newInt32Array(sharedBuffer);// Atomics.and()const originalAndValue = Atomics.and(sharedArray,0,0b1010);
    console.log(Atomics.and: Original value: ${originalAndValue}, New value: ${sharedArray[0].toString(2)});

    Output

    Atomics.and: Original value: 5, New value: 0
    

    Atomics.or()

    // Shared memory setupconst sharedBuffer =newSharedArrayBuffer(4);const sharedArray =newInt32Array(sharedBuffer);// Atomics.or()const originalOrValue = Atomics.or(sharedArray,0,0b1100);
    console.log(Atomics.or: Original value: ${originalOrValue}, New value: ${sharedArray[0].toString(2)});

    Output

    Atomics.or: Original value: 0, New value: 1100
    

    Atomics.xor()

    // Shared memory setupconst sharedBuffer =newSharedArrayBuffer(4);const sharedArray =newInt32Array(sharedBuffer);// Atomics.xor()const originalXorValue = Atomics.xor(sharedArray,0,0b0110);
    console.log(Atomics.xor: Original value: ${originalXorValue}, New value: ${sharedArray[0].toString(2)});

    Output

    Atomics.xor: Original value: 12, New value: 1010
    

    Atomics.load()

    // Shared memory setupconst sharedBuffer =newSharedArrayBuffer(4);const sharedArray =newInt32Array(sharedBuffer);// Atomics.load()const loadedValue = Atomics.load(sharedArray,0);
    console.log(Atomics.load: Loaded value: ${loadedValue});

    Output

    Atomics.load: Loaded value: 10
    

    Atomics.store()

    // Shared memory setupconst sharedBuffer =newSharedArrayBuffer(4);const sharedArray =newInt32Array(sharedBuffer);// Atomics.store()
    Atomics.store(sharedArray,0,42);
    console.log(Atomics.store: New value: ${sharedArray[0]});

    Output

    Atomics.store: New value: 42
    

    Atomics.exchange()

    // Shared memory setupconst sharedBuffer =newSharedArrayBuffer(4);const sharedArray =newInt32Array(sharedBuffer);// Atomics.exchange()const originalExchangeValue = Atomics.exchange(sharedArray,0,99);
    console.log(Atomics.exchange: Original value: ${originalExchangeValue}, New value: ${sharedArray[0]});

    Output

    Atomics.exchange: Original value: 42, New value: 99
    

    Atomics.compareExchange()

    // Shared memory setupconst sharedBuffer =newSharedArrayBuffer(4);const sharedArray =newInt32Array(sharedBuffer);// Atomics.compareExchange()const expectedValue =99;const newValue =55;const successfulCompareExchange = Atomics.compareExchange(sharedArray,0, expectedValue, newValue);
    console.log(Atomics.compareExchange: Operation was${successfulCompareExchange ? ' ' : ' not '}successful. New value: ${sharedArray[0]});

    Output

    Atomics.compareExchange: Operation was successful. New value: 55
    

    Atomics.wait()

    // Shared memory setupconst sharedBuffer =newSharedArrayBuffer(4);const sharedArray =newInt32Array(sharedBuffer);// Atomics.wait()const valueToWaitFor =55;
    Atomics.store(sharedArray,0, valueToWaitFor);setTimeout(()=>{
    
    Atomics.notify(sharedArray,0);},2000);const waitResult = Atomics.wait(sharedArray,0, valueToWaitFor,5000);
    console.log(Atomics.wait: Wait result: ${waitResult});

    Output

    Atomics.wait: Wait result: timed-out
    

    Example 2: Real-World Use Case – Synchronized Counter

    In this real-world scenario, we employ the Atomics object to construct a synchronized counter; multiple threads increment this counter through the use of the Atomics.add() operation, thus guaranteeing atomicity in our update process. The functionality and necessity for effective thread coordination become evident with such an application: it offers practical data management solutions within a multi-threaded environment.

    const sharedBuffer =newSharedArrayBuffer(4);const sharedArray =newInt32Array(sharedBuffer);// Synchronized counterfunctionincrementCounter(){const incrementValue =1;const originalValue = Atomics.add(sharedArray,0, incrementValue);
      console.log(Incremented counter by ${incrementValue}. New value: ${sharedArray[0]});}// Multiple threads incrementing the countersetInterval(()=>{incrementCounter();},1000);// Simulate other activities in the main threadsetInterval(()=>{
      console.log('Main thread doing other work.');},3000);

    Output

    Incremented counter by 1. New value: 1
    Incremented counter by 1. New value: 2
    Main thread doing other work.
    Incremented counter by 1. New value: 3
    Incremented counter by 1. New value: 4
    Incremented counter by 1. New value: 5
    Main thread doing other work.
    Incremented counter by 1. New value: 6
    Incremented counter by 1. New value: 7
    Incremented counter by 1. New value: 8
    Main thread doing other work.
    ...
  • Ajax

    Asynchronous JavaScript and XML (Ajax) represents a web development technique: it enables dynamic, interactive communication between server and webpage without necessitating complete page reload. The descriptor “asynchronous” underlines that data exchanges can occur in the background, independent of user experience disruption. Rather than idly awaiting full-page refreshment; Ajax empowers real-time updates on specific sections of a webpage, thus yielding an interface that is more seamless and responsive.

    How Ajax works?

    The central role in enabling dynamic updates, without the necessity of a full page reload, belongs to the XMLHttpRequest object within JavaScript’s Ajax functionality. This particular process allows for asynchronous communication between server and web page. The server responds with data, usually in JSON or XML format when receiving a request sent by this object. Processing this data is the task of JavaScript; it updates specific portions of the webpage in real-time. The asynchronous nature which is a critical feature for modern web development ensures these operations occur unobtrusively in background, thereby enhancing interactivity by allowing data to be fetched and sent asynchronously.

    Here, we will to explore Ajax to get a deeper understanding of it.

    There are 4 approaches to make Ajax calls or to implement Ajax in JavaScript and they are:

    • XMLHttpRequest (Older Approach)
    • Fetch API (Modern Approach)
    • Axios (Library for HTTP Requests)
    • jQuery Ajax

    We will be using JSONPlaceholder in all the examples for understanding purposes.

    JSONPlaceholder is an open-source and simulated REST API provider which lets developers test their prototype applications. It returns fake/dummy data for various resources like users, posts, comments etc. The API endpoints of JSONPlaceholder can be made using HTTP requests and they will be mimicking the nature of real APIs without any need for authentication. Our goal here is to use these APIs/endpoints to under Javascript-Ajax.

    Using XMLHttpRequest

    The Native JavaScript approach using XMLHttpRequest represents the oldest method for asynchronous requests. It relies on the XMLHttpRequest object to create and send HTTP requests. This method involves setting up callback functions to handle various states of the request, making it suitable for simpler scenarios. However, it has some limitations compared to more modern approaches.

    Example

    <!DOCTYPE html><html lang="en"><body><p>Native XMLHttpRequest Example</p><button onclick="nativeAjax()">Make Request</button><pre id="result"></pre><script>functionnativeAjax(){var xhr =newXMLHttpRequest();
    
    xhr.open('GET','https://jsonplaceholder.typicode.com/users/2',true);
    xhr.onreadystatechange=function(){if(xhr.readyState ==4&amp;&amp; xhr.status ==200){var responseData =JSON.stringify(JSON.parse(xhr.responseText),null,2);
        document.getElementById('result').innerText ='Native XMLHttpRequest:\n'+ responseData;}};
    xhr.send();}&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;</pre>

    Using Fetch API

    Presenting a modern alternative to XMLHttpRequest, the Fetch API offers a more straightforward and powerful syntax; it returns Promises thus enhancing the intuitive handling of asynchronous operations. Supporting an extensive array of HTTP methods and headers: this provides developers with a cleaner, concise method for making asynchronous requests. Contemporary JavaScript applications often prefer it for its clarity and ease of use.

    Example

    <!DOCTYPE html><html><body><h1>Fetch API Example</h1><button onclick="fetchApi()">Make Request</button><pre id="result"></pre><script>functionfetchApi(){fetch('https://jsonplaceholder.typicode.com/users/3').then(response=>{if(!response.ok){thrownewError('Network response was not ok');}return response.json();}).then(data=>{var formattedData =JSON.stringify(data,null,2);
    
        document.getElementById('result').innerText ='Fetch API:\n'+ formattedData;}).catch(error=&gt;{
        document.getElementById('result').innerText ='Fetch API Error: '+ error.message;});}&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;</pre>

    Using Axios

    Designed for making HTTP requests, Axios emerges as a popular JavaScript library. Its popularity is largely due to its clean and concise syntax: built on Promises; furthermore, it boasts automatic JSON data transformation support features that set it apart from other libraries in the field. Offering more than just basic functionality, Axios presents advanced features such as request and response interceptors, a robust selection for managing AJAX operations within the context of modern web development environment.

    Example

    <!DOCTYPE html><html><head><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script></head><body><h1>Axios Example</h1><button onclick="axiosExample()">Make Request</button><pre id="result3"></pre><script>functionaxiosExample(){
    
    axios.get('https://jsonplaceholder.typicode.com/users/5').then(response=&gt;{var formattedData =JSON.stringify(response.data,null,2);
        document.getElementById('result3').innerText ='Axios:\n'+ formattedData;}).catch(error=&gt;{
        document.getElementById('result3').innerText ='Axios Error: '+ error.message;});}&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;</pre>

    Using Ajax jQuery

    The $.ajax method in jQuery simplifies the AJAX request process: a popular approach previously; however, its usage has waned alongside modern JavaScript's ascent. Offering an interface that is both consistent and cross-browser compatible, jQuery Ajax remains suitable for projects already using or needing specific features of jQuery due to these advantages it presents. However, for new projects, modern alternatives may be preferred.

    Example

    <!DOCTYPE html><html><head><script src="https://code.jquery.com/jquery-3.6.4.min.js"></script></head><body><h1>jQuery Ajax Example</h1><button onclick="jqueryAjax()">Make Request</button><pre id="result4"></pre><script>functionjqueryAjax(){
    
    $.ajax({
      url:'https://jsonplaceholder.typicode.com/users/7',
      method:'GET',
      dataType:'json',success:function(data){var formattedData =JSON.stringify(data,null,2);
        document.getElementById('result4').innerText ='jQuery Ajax:\n'+ formattedData;},error:function(xhr, status, error){
        document.getElementById('result4').innerText ='jQuery Ajax Error: '+ error;}});}&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;</pre>

    Ajax Use Cases

    In real-world scenarios, developers commonly employ Ajax to create web applications that are both responsive and interactive. A pertinent example: a social media platform; here, users have the ability - thanks to Ajax, to add or load new comments in the background without needing an entire page refresh. Dynamic updating ensures a user experience that is smooth and uninterrupted, permitting individuals to engage with content and one another seamlessly. This process yields a platform more responsive and engaging; it amplifies user interaction thus enhancing satisfaction.

    Prominent companies utilizing Ajax for enhanced user experiences include Google (Gmail, Maps), Facebook, Twitter, Amazon, Netflix, GitHub, LinkedIn, YouTube, Microsoft Office Online, and Uber. Ajax is employed for real-time updates, dynamic content loading, and seamless interactions on their respective platforms.