daniel.sedlacek
daniel.sedlacek

Reputation: 8619

What would cause XMLHttpRequest to hang without error until browser default timeout?

I am a front end developer with limited knowledge of how networks work.

When Javascript's XMLHttpRequest times out the ontimeout handler is triggered.

Unless the XMLHttpRequest.timeout property is set (supported in modern browsers), the request waits for the browsers default time limit (which is 300 seconds / 5 minutes in Chrome).

If I send a request to a non-existing address or a server that is down there will be an error response, right?

My question is, what network or server condition will cause the request to hang until timed out, as opposed to quickly returning an error response?

Upvotes: 1

Views: 1101

Answers (3)

TheChetan
TheChetan

Reputation: 4596

Introduction

Generally, on the server side you have a thread pool or some event queue to handle incoming requests (lets call this the IO thread pool). The actual processing of the request happens on another thread (the main thread, if single threaded). Let's call this the processing thread pool. On the processing thread, the request is processed quickly and a response is returned to the IO thread thread. This is a simplified version of the request response anatomy.

----------        -----------------       ------------------       ---------------------
| client | <----> | load balancer | <---> | request thread | <---> | processing thread |
----------        -----------------       ------------------       ---------------------

When the client sends a request to the server, it get's accepted by the request thread pool and has to wait for until the server can process the incoming request. There may be a delay for a variety of reasons, like being blocked by a long running database query or performing expensive computations like 3D rendering etc. But more often than not, this happens because something is wrong like unclosed resources that are eating away from the processing thread pool.


Example

Let's try an example, here is a simple server written in node using the express framework. In node there is just a single thread for processing, the main thread. Let's see what happens when that thread is blocked.

const express = require('express')
const app = express();
const port = 3000;

var sleep = function(seconds) {
    var waitTill = new Date(new Date().getTime() + seconds * 1000);
    while(waitTill > new Date()){}
};

app.get('/slow', (req, res) => {
    // The sleep here signifies that process is taking a long time for whatever reason
    sleep(1);
    res.send('Slow query returns');
});

app.get('/fast', (req, res) => {
    res.send('Fast query returns');
});

app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
});

Let's build a simple client to do test the application.

var unirest = require('unirest');
var i = 0;
var j = [];
var tot = 20;
for (var i=0; i < tot; i++) {
    j = j.concat(i);
}

j.forEach(function(i) {
    console.time("No: " + i);
    unirest('GET', 'http://localhost:3000/fast')
        .end(function (res) { 
            if (res.error) throw new Error(res.error); 
            console.timeEnd("No: " + i);
        });
});

j.forEach(function(i) {
    console.time("No: " + (i+tot));
    unirest('GET', 'http://localhost:3000/slow')
        .end(function (res) { 
            if (res.error) throw new Error(res.error); 
            console.timeEnd("No: " + (i+tot));
        });
});

Output from the client:

No: 0: 31.406ms
No: 1: 31.203ms
No: 3: 31.171ms
No: 2: 31.628ms
No: 4: 31.662ms
No: 5: 31.835ms
No: 7: 31.703ms
No: 6: 32.288ms
No: 8: 32.295ms
No: 9: 32.459ms
No: 10: 1027.011ms
No: 11: 2027.326ms
No: 12: 3027.625ms
No: 13: 4027.925ms
No: 15: 5027.833ms
No: 14: 6028.303ms
No: 16: 7028.411ms
No: 18: 8030.380ms
No: 17: 9030.837ms
No: 19: 10030.692ms

As you can see, the slow query takes time to run (a whole 10 seconds for the 10th request sent) and you can extrapolate this to as long as required.


What can go wrong?

  1. Long running database query that blocks the processing thread from returning any response
  2. Infinite loop blocks a thread rendering it useless, hence shrinking the size of the processing thread pool
  3. Too many objects created in the ram that leads to the Garbage collector running often that blocks the processing thread pool. This type of problem occurs especially with unclosed file pointers and lingering references to objects that should have been destroyed
  4. Deadlocks that can trying to get a shared resource which blocks multiple threads in the processing thread pool

The above list is not exhaustive by any means. Anything you think can go wrong probably will.

While the processing thread pool is busy catering to older requests, the request thread pool continues to accept new connections and stall them out until the server crashes. Hence your server can take abnormally long to respond. But this is universally a bad sign.

Upvotes: 2

miknik
miknik

Reputation: 5941

An XMLHttpRequest timeout ProgressEvent is dispatched if:

The author specified timeout has passed before the fetch completed.

So the network or server conditions which will cause the request to hang are basically any which result in a long time to return a response.

  • Slow server
  • Huge response payload
  • Loss of network connection
  • Slow client network connection

etc etc

If I send a request to a non-existing address or a server that is down there will be an error response, right?

The non existing address will probably return an error from your DNS server, so you should be good there. A server that is down won't do anything, it's down. What happens there is between your timeout setting and the redundancy of the server you are trying to access

Upvotes: 3

MauriceNino
MauriceNino

Reputation: 6747

There are many reasons why a request might time out. The simplest one being, that the connection is bad and it takes too long to get a response back.

I don't know what you are exactly looking for and why you need this information to begin with, but you get an error response quickly, if the URL you are trying to reach does not exist. For example if you try to request something from http://asdahgo8fgasidf.com/ (does not exist).

A valid use-case for requests that time out is long polling. This is when you are sending a request to a server, but it doesn't give an answer until it has one. For example while checking for new messages in a messenger app. If the request timed out, the client just sends a new one. This is to ensure that you get an update as soon as there is one available.

Upvotes: 1

Related Questions