Tips for executing a callback in an asynchronous manner

I wrote a JavaScript function named fetchAandB that accepts a callback as a parameter. This function first makes an ajax call to retrieve the value 'a'. Once it gets the value, it invokes the callback function with 'a' passed as an argument. The callback then retrieves the value 'b' and logs both 'a' and 'b' in the console. As a result, I see

{"key":"a"} {"key":"b"}
displayed in the console.

Initially, I assumed that the two ajax calls would be executed simultaneously or asynchronously. However, it seems that they are running synchronously, one after the other.

Below, you can find the JavaScript code for the ajax requests:

index.html:

<script>
    function fetchAandB(callback){
        const xhr = new XMLHttpRequest();
        xhr.open('GET', './ajax-a.php', true);
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4 && xhr.status === 200){
                callback(xhr.responseText)
            }
        }
        xhr.send();
    }

    function callback(resultA){
        const xhr = new XMLHttpRequest();
        xhr.open('GET', './ajax-b.php', true);
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4 && xhr.status === 200){
                const resultB = xhr.responseText;
                console.log(resultA, resultB);
            }
        }
        xhr.send();
    }
    fetchAandB(callback);
</script>

ajax-a.php:

<?php
sleep(5);
$response = [
    "key" => "a",
];
echo json_encode($response);

The code for ajax-b.php is identical to ajax-a.php except that the value of $response.key is 'b' instead of 'a'.

I expected the above code to trigger ajax calls simultaneously for 'a' and 'b'. However, when the PHP script sleeps for 5 seconds in both ajax-a.php and ajax-b.php, it takes a total of 10 seconds for the console.log output to appear. If only one of the scripts sleeps for 5 seconds, then it takes 5 seconds for the output to display.

Is there a way to utilize callbacks to combine the results of ajax calls like this while ensuring that the individual calls execute simultaneously or asynchronously? Or is this not achievable using callbacks?

Answer №1

If you wish for the request to ajax-b to be sent at nearly the same time as the request for ajax-a, it is important to make the respective calls to xhr.send() almost simultaneously.

Currently, the call to ajax-b's send() occurs within the callback() function after you have already received the response for ajax-a.


You will then need to integrate additional logic to determine when both responses have been received so that you can log both sets of data together (if desired).

To achieve this using your existing approach, a simple method would be like the following:

function getA(callback){
    const xhr = new XMLHttpRequest();
    xhr.open('GET', './ajax-a.php', true);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.onreadystatechange = function(){
        if(xhr.readyState === 4 && xhr.status === 200){
            callback(xhr.responseText)
        }
    }
    xhr.send();
}

function getB(callback){
    const xhr = new XMLHttpRequest();
    xhr.open('GET', './ajax-b.php', true);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.onreadystatechange = function(){
        if(xhr.readyState === 4 && xhr.status === 200){
            const resultB = xhr.responseText;
            callback(xhr.responseText)
        }
    }
    xhr.send();
}

function getAandB() {
    const data = [];

    function callback(responseData) {
        data.push(responseData);
        if (data.length === 2) {
            console.log(...data);
        }
    }

    getA(callback);
    getB(callback);
}

getAandB();

However, there are now more efficient tools available such as promises and modern APIs like fetch which natively support them.

async function getAandB() {
    const dataPromises = [
        fetch("./ajax-a.php").then(r => r.text()),
        fetch("./ajax-b.php").then(r => r.text())
    ];
    const data = await Promise.all(dataPromises);
    console.log(...data);
}
getAandB();

Answer №2

After attempting to make edits to my question, I encountered the message 'the edit queue was full'.

It took me some time to grasp @Quentin's response, but I eventually understood that it depends on both instances of the callback function modifying the same variable (which I believe is known as passing by reference and is the default behavior with arrays). With this understanding, even though the instances are unaware of each other, it is feasible to ascertain when both ajax calls have finished by checking if the data array has been updated twice. If so, then both calls must have completed and the data can be outputted using console.log.

The getAandB function becomes unnecessary. A simpler and less convoluted code that achieves the same result as Quentin's answer is as follows:

<script>
const data = [];

function getA(){
    const xhr = new XMLHttpRequest();
    xhr.open('GET', './ajax-a.php', true);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.onreadystatechange = function(){
        if(xhr.readyState === 4 && xhr.status === 200){
            data.push(xhr.responseText);
            if (data.length === 2){
                console.log(...data);
            }
        }
    }
    xhr.send();
}

function getB(){
    const xhr = new XMLHttpRequest();
    xhr.open('GET', './ajax-b.php', true);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.onreadystatechange = function(){
        if(xhr.readyState === 4 && xhr.status === 200){
            data.push(xhr.responseText);
            if (data.length === 2){
                console.log(...data);
            }
        }
    }
    xhr.send();
}

getA();
getB();

</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Confirm before closing the window

How can I get this code to function properly and show a confirmation alert after the user clicks on a button? This is essentially an "exit website button". The confirmation pop-up will have: If "OK" is clicked > the current window will close; If ...

Managing dependencies with Yarn or npm

While experimenting with remix and mui v5, I encountered some issues. When using npm and running npm run dev, I received the following error: Error: Directory import '.../playground/remix-mui-dev/node_modules/@mui/material/styles' is not supporte ...

Testing React Hook Form always returns false for the "isValid" property

When creating a registration modal screen, I encountered an issue with the isValid value when submitting the form. In my local environment (launched by npm start), the isValid value functions correctly without any issues. However, during unit testing us ...

What is the best way to keep an object in an array?

I am faced with the challenge of merging two arrays and converting them into objects stored in one array. const name = ["Amy", "Robert", "Sofie"]; const age = ["21", "28", "25"]; The desired output: const person =[{name: 'Amy', age: '21&apo ...

What is causing my "mapDispatchToProps" to not recognize my action function?

Could someone please explain why I am receiving an error stating "getOnEvents() is not a function" when I call this.props.getOnEvents()? I can see the function in the props when I log it to the console, but for some reason, it throws an error when I try to ...

Ways to retrieve AJAX variables from outside the AJAX function

$(document).ready(function() { var items; $.ajax({ url: 'item/getProducts', dataType: 'json', success: function(data){ items=data; ...

The rendering of the input dropdown control in Angular JS is experiencing difficulties

I am currently using your Angular JS Input Dropdown control, and I have followed the code example provided on your demo page in order to implement the control on a specific page of my website built with PHP Laravel. However, I have encountered an issue dur ...

Encountering a 400 bad request error while trying to post data using

const fetch = require("node-fetch").default; let iApi = express.Router(); iApi.post("/update/:name/:value", async (req, res) => { const name = req.params["name"]; ...

Waiting for the asynchronous fetch operation to finish in a webpacked application block

Currently, I am facing an issue where I need to block the fetching of an external JSON file so that a configuration object can be consumed elsewhere. This process involves three files: builder.jsx runtime.jsx and a JSON file: config.settings.json In t ...

How to use a self-hosted font in a custom Material-UI theme for ReactJS?

Currently, I am in the process of setting up my initial project utilizing Material-UI for ReactJS. My intention is to personalize the default theme by incorporating a custom font (from the server, not sourced from Google Fonts or anything similar). Despite ...

Is there a way to use XMLhttprequest to send a post request to my personal Node server using vanilla javascript?

I have encountered an issue while trying to send data to Node using XMLhttprequest. The data I am attempting to send looks like this (/q/zmw:95632.1.99999.json). My connection to Node is set up correctly, but I was receiving an empty object. So, I decided ...

- Determine if a div element is already using the Tooltipster plugin

I have been using the Tooltipster plugin from . Is there a way to check if a HTML element already has Tooltipster initialized? I ask because sometimes I need to update the text of the tooltip. To do this, I have to destroy the Tooltipster, change the tit ...

Refreshing the page by clicking on a checkbox, eliminating the need for a submit

I'm currently in the process of developing an online shopping website and I'm relatively new to Ajax and jQuery. One issue that I've encountered is related to the selection of colors for t-shirts, which are as follows: 1. Red 2. Blue 3. G ...

Switch vue-multiselect on/off with the click of a button

Upon clicking the button, a multiselect menu pops up. However, on a second click, the true/false values quickly flash and the isOpen status remains true. What could be causing this issue? Here is the template: <div id="app"> <button @click="to ...

Vue3 Event Handling - Attempt to access an undefined property while rendering the component

Just starting out with Vue and JavaScript, but making progress! Currently working on a Vue Main App that includes a sub-component for a form (specifically to calculate the difference between 2 values). I want the form values to reset to their initial sta ...

Here's a new version: "Strategies for deactivating a text field in a desktop application that

I am currently using WiniumDriver to automate a desktop application. My goal is to disable a text field once a value has been entered into it. // Launch the desktop application WiniumDriver driver = null; DesktopOptions option = new DesktopOptions(); o ...

What is the best way to change an http call in a controller to a Service/factory pattern that accepts a parameter?

Currently, I have a controller making use of http.get, http.push and http.post methods within my AngularJS app. During my learning journey with AngularJS, I've discovered that it's more efficient to place http.get calls in service files. While I ...

Transmitting information from directive to parent scope controller

I've successfully implemented a directive that generates a Google map on the page. Now, my goal is to pass the map object back out of the directive and into the parent controller. This will allow me to utilize it in various methods as needed. While ...

ng-model in html input with a name of "foo[]"

Apologies for the lack of a more specific title. In HTML, when we need multiple values for a given name, we utilize the name="foo[]" attribute. Upon posting the data, it arrives as an array. I am seeking this same functionality with ng-model in Angular. ...

Tips for transferring an array of objects from an input field to a new array in JavaScript

In my current React project, I am facing a challenge with a text input that needs to accept values multiple times. The interface on the screen is set up like this: https://i.sstatic.net/Q19Tp.png Upon clicking "Next", the value entered will be submitted ...