Is the xmlhttprequest timeout/abort feature not functioning as anticipated?

Check out this snippet of my AJAX function:

/**
 * This function initiates an AJAX request
 *
 * @param url      The URL to call (located in the /ajax/ directory)
 * @param data     The data to send (will be serialized with JSON)
 * @param callback The function to execute with the response text
 * @param silent   If true, errors will not be displayed to the user
 * @param loader   The element containing the message "Loading... Please wait"
 */
AJAX = function(url,data,callback,silent,loader) {
    var a,
        attempt = 0,
        rsc = function() {
            if( a.readyState == 4) {
                if( a.status != 200) {
                    if( a.status > 999) { // Sometimes IE throws 12152 error
                        attempt++;
                          if( attempt < 5)
                            send();
                        else if( !silent) {
                            alert("HTTP Error "+a.status+" "+a.statusText+"<br />Failed to access "+url);
                        }
                    }
                    else if(!silent) {
                        alert("HTTP Error "+a.status+" "+a.statusText+"\nFailed to access "+url);
                    }
                }
                else {
                    callback(JSON.parse(a.responseText));
                }
            }
        },
        to = function() {
             
            a.abort();
            attempt++;
            if( attempt < 5)
                send();
            else if( !silent) {
                alert("Request Timeout\nFailed to access "+url);
            }
        };
    data = JSON.stringify(data); 
    var send = function() {
        if( loader && attempt != 0) {
            loader.children[0].firstChild.nodeValue = "Error... retrying...";
            loader.children[1].firstChild.nodeValue = "Attempt "+(attempt+1)+" of 5";
        }

        a = new XMLHttpRequest(); 
        a.open("POST","/ajax/"+url,true);
        a.onreadystatechange = rsc;
        a.timeout = 5000;
        a.ontimeout = to;
        a.setRequestHeader("Content-Type","application/json");
        a.send(data);

        
    };
    send();
};

The main intent behind this function is to try the request up to five times. There are cases where IE throws unusual HTTP errors and servers may fail to respond.

I've noticed that the abort() method does not seem to stop the connection as expected. To confirm, I created a simple PHP script:

<?php
    sleep(60);
    touch("test/".uniqid());
    die("Request completed.");
?>

With the code above, a file is generated using the current uniqid(), helping me track when the sleep(60) finishes.

Expected outcome:

The request gets sent
After five seconds, the message changes to "Error... Retrying... Attempt 2/5"
This continues until Attempt 5/5, leading to failure.
All the requests to the PHP file should be aborted, resulting in either five files in the "test" folder, spaced 5 seconds apart, or none, assuming ignore_user_abort is disabled.

Observed behavior (in IE9):

The request is made
The attempts display correctly as intended
After five tries, an error message appears
Then, I cannot load any pages for five minutes straight.
On the server side, there are five files spaced one minute apart

I'm puzzled by this situation because on the server end, Requests 3, 4, and 5 are being executed minutes after the "Timeout" message pops up on the browser.

If it's relevant, the page executing these AJAX calls is inside an iframe. Reloading the iframe (using

iframe.contentWindow.location.reload()
) does NOT resolve the issue—it still waits for those five requests to complete.

Why is this issue occurring and how can it be resolved?

EDIT: For further investigation, I ran the test again while monitoring network activity with Developer Tools. Here are the results:

URL          Method   Result     Type   Received  Taken   Initiator
/ajax/testto          (Aborted)              0 B  < 1 ms (Pending...)
/ajax/testto          (Aborted)              0 B  125 ms (Pending...)
/ajax/testto          (Aborted)              0 B  125 ms (Pending...)
/ajax/testto          (Aborted)              0 B  125 ms (Pending...)
/ajax/testto          (Aborted)              0 B  124 ms (Pending...)

Answer №1

It appears that a limitation exists with the timeout and ontimeout not being fully implemented in certain scenarios:

var hasTimeout = 'timeout' in new XMLHttpRequest(); // returns false

This issue is evident in Chrome 16 and Firefox 7 where the expected result should be true based on the specified criteria:

The timeout attribute should return its assigned value, initially set to zero.

While these features have been outlined in the XHR 2 specification since September 7, 2010, they are still categorized under the "Working Draft" phase as indicated by the document released on February 25, 2008. Hence, the alignment of implementations with this spec may vary.


In cases where these functionalities are unavailable, an alternative approach could involve leveraging onabort and setTimeout (as highlighted in your comment):

// snip

to = function() {
    attempt++;
    if( attempt < 5)
        send();
    else if( !silent) {
        console.log("Request Timeout\nFailed to access "+url);
    }
};

// snip

var send = function() {
    if( loader && attempt != 0) {
        loader.children[0].firstChild.nodeValue = "Error... retrying...";
        loader.children[1].firstChild.nodeValue = "Attempt "+(attempt+1)+" of 5";
    }
    a = new XMLHttpRequest();
    a.open("POST","/ajax/"+url,true);
    a.onreadystatechange = rsc;
    setTimeout(function () {     /* vs. a.timeout */
        if (a.readyState < 4) {
            a.abort();
        }
    }, 5000);
    a.onabort = to;              /* vs. a.ontimeout */
    a.setRequestHeader("Content-Type","application/json");
    a.send(data);
    console.log('HTTP Requesting: %s', url);
};

// snip

For demonstration, refer to this example link -- The ?delay=2 scenario should complete successfully, while the ?delay=10 situation reaches the retry limit after 5 attempts.

Answer №2

After executing your code, I encountered the error c00c023f. Upon further investigation, I stumbled upon a potential solution:

It seems like this issue bears resemblance to what you're currently facing.

Furthermore, there is a related inquiry on Stack Overflow that addresses the same issue and provides a resolution (referenced from the aforementioned link): IE 9 Javascript error c00c023f

Answer №3

To prevent the request from being aborted prematurely, consider implementing the following steps:

request.onreadystatechange = function() {};

Additionally, ensure to include a conditional check before calling the abort function:

if( request.readyState > 0 && request.readyState < 4 ) {
    request.abort();
}

Answer №4

Encountered a similar issue which was traced back to a problem with PHP session handling. When a session is active, all subsequent requests from the same session are forced to wait.

<?php
    session_write_close();
    sleep(60);
    touch("test/".uniqid());
    die("Request completed.");
?>

This solution wouldn't be of any use if you haven't initiated the session in the first place :)

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

PugJS is failing to properly interpolate numbers from the JSON file

My goal is to display a list of interfaces retrieved from my router API, which is in JSON format. However, when using Pug, only the strings are being rendered and not the numbers. Here is the output (it displays correctly in HTML): em1 192.168.0.0/24 Addr ...

express-session is failing to maintain persistence and refusing to transmit a cookie to the browser

I am currently developing a web application using the MERN stack (React, Node.js, Express, and MongoDB). I have integrated express-session in my Node.js project, but for some reason, I cannot see the connect.sid cookie in the browser. Additionally, it appe ...

The planebuffergeometry does not fall within the three namespace

I am currently working on a project using three.js and next.js, but I keep encountering this error: 'planeBufferGeometry is not part of the THREE namespace. Did you forget to extend? See: As a beginner in three.js, I'm unsure what exactly is ca ...

Why is it that PHP is used to retrieve the database value, JavaScript increments it, and AJAX saves it back to the database, yet it resets to 0.0 upon page refresh?

I am in the process of creating a page for setting temperature targets. The form allows users to adjust the target temperature by increments of 0.5 using JavaScript buttons. Once the user is satisfied with the new target, they can click 'set' whi ...

What is the process for generating a fresh instance of an Angular service?

Hey there, I've been pondering a solution to a little dilemma I'm facing. Let me share my thoughts and see if you can lend some insight or tell me where I might be going astray. Setting the Stage: In the realm of angular app creation, it's ...

Pagination with React Material UI is a user-friendly and visually

Requirement Within the Material UI framework, I need to implement pagination functionality by clicking on the page numbers (e.g., 1, 2) to make an API call with a limit of 10 and an offset incrementing from 10 after the initial call. https://i.stack.imgur. ...

Using Angular 4 to import an HTML file

I am trying to save test.svg in a component variable 'a' or svgicon.component.html. To achieve this, I have created the svgicon.component.ts file. However, it's not working. What steps should I take next? svgicon.component.ts import ...

Vue plugins that emit events

In the scenario where I have a basic Vue plugin that does not contain any components, but simply provides some methods to the user: export default { install(Vue, options) { // Unrelated tasks go here. } Vue.prototype.$foo = () => { ...

Tips for accessing a web service using JavaScript (AJAX)

I have two projects: one is a web service and the other is an ASP.NET web project. I am trying to insert data using JSON (with AJAX). I tested the web service file with code behind and it works fine, but I'm encountering an error with the JavaScript ...

Craft an interactive Bootstrap 4 Accordion featuring content retrieved through an Ajax request

I am currently working on setting up a Bootstrap 4 Accordion. Utilizing an Ajax call to fetch the data, I can see the data being logged correctly in the console. My objective is to iterate through the data using a forEach loop and add a new card to the Acc ...

A step-by-step guide on uploading a CSV file in Angular 13 and troubleshooting the error with the application name "my

I am currently learning angular. I've generated a csv file for uploading using the code above, but when I try to display it, the screen remains blank with no content shown. The page is empty and nothing is displaying Could it be that it's not ...

Using a Javascript library within an Angular component: A comprehensive guide

I've been working on a Web-Client project that involves visualizing sensor data such as velocity and acceleration within a coordinate system. In order to display this coordinate system, I decided to use the graph.js library from https://github.com/dhu ...

javascript An interactive accordion component created with Bootstrap

I have been searching for a solution to create an accordion-style collapsible set of panels where the panels remain separate and do not have headers. I want buttons on one side, and when clicked, a panel is displayed on the other side. Only one panel shoul ...

What is the best way to programmatically route or navigate to a specific route within a Next.js class component?

tag: In the process of creating my app with next.js, I primarily use functional components. The sole exception is a class component that I utilize to manage forms. Upon form submission, my goal is to redirect back to the home page. However, when I attemp ...

Can pins be added or removed from a location plan (image or vector) using either Javascript or the DevExpress library?

At the factory where I am employed, there are close to 1000 cameras in operation. I have requested to have the locations of these cameras marked on a non-geographical map of the factory. By simply clicking on one of the camera icons, it should be possible ...

Using the mt-downloader module in a Node application is a straightforward process

Hey there, I'm looking to incorporate the Multi downloader module into my project. I've checked out the GitHub link, but unfortunately, there are no examples provided on how to actually use this module. I came across this example and tried implem ...

The desired outcome is not displayed following the Ajax post request

I have created an app that utilizes asynchronous AJAX requests to enable seamless chat functionality without refreshing the page. However, I'm facing an issue where the messages are not being displayed. When I inspect the network tab and navigate to t ...

Finding the final day of a specific year using the moment library

When it comes to determining the last day of a year, hard-coding the date as December 31st seems like a simple solution. While there are various methods using date, js, and jquery, I am tasked with working on an Angular project which requires me to use mom ...

The message sent back by Django Rest Framework is: "a legitimate integer must be provided"

I have integrated a react form within my Django application, supported by the rest framework in the backend. When I submit the form without entering any value in the integer field, I encounter the following error message from the rest API: "a valid integer ...

Show component depending on the lifecycle of another component

I recently encountered a problem with one of my custom components. I developed a "Chargement" Component (Loading in French) for a project I am currently working on. The component is a basic circular spinner with a dark background that indicates to the use ...