16
votes

Hi I understand that in long polling you keep the connection with the server open for long till you a get a response back from the server and then poll again and wait for the next response. However i dont seem to understand how to code it. There is this code below which uses long polling but I dont seem to get it

(function poll(){
$.ajax({ url: "server", success: function(data){
   //update page based on data

}, dataType: "json", complete: poll, timeout: 30000 });
})();

But how is the connection kept open here. I understand that "poll" function is fired again once the response from the server is got.But how is the connection kept open?

Edit1:- It would be great if someone can also explain what would timeout actually do here

7
Maybe the connection is not kept open....rene
how do you prevent the server from closing the connection. If the request is sent to the server, it will respond and then the conn will automatically be closedRasmus
@itamecodes: You write your server so that it doesn't respond until it has data to respond with.Eric
possible duplicate of Simple "Long Polling" example code?Joe
I think that this person got the example from techoctave.com/c7/posts/… which is an article that seems to make no sense. It gives almost the same example twice and says one is long polling when it isn't!Luke

7 Answers

15
votes

The client cannot force the server to keep the connection open. The server is simply not closing the connection. The server will have to say at some point "that's it, there's no more content here, bye". In long polling, the server simply never does so and keeps the client waiting for more data, which it trickles out little by little as updates come in. That's long polling.

On the client side it's possible to check occasionally for the data which has already been received, while the request has not finished. That way data can occasionally be sent from the server over the same open connection. In your case this is not being done, the success callback will only fire when the request has finished. It's basically a cheap form of long polling in which the server keeps the client waiting for an event, sends data about this event and then closes the connection. The client takes that as the trigger, processes the data, then reconnects to the server to wait for the next event.

9
votes

I think what is making this confusing to understand is that the discussion is focused on the client-side programming.

Long-polling is not strictly a client-side pattern, but requires the web server to keep the connection open.

Background: Client wants to be notified by web server when something occurs or is available, for example, let me know when a new email arrives without me having to go back and ask every few seconds.

  1. Client opens a connection to a specific URL on the web server.
  2. Server accepts connection, opens a socket and dispatches control to whatever server-side code handles this connection (say a servlet or jsp in java, or a route in RoR or node/express).
  3. Server code waits until the event or information is available. For example, when an email arrives, sees if any of the "waiting connections" are for the particular inbox. If they are, then respond with the appropriate data.
  4. Client receives data, does its thing, then starts another request to poll.
3
votes

I was looking to do something with staggered data results where some would come back right away but the last few results might come back 10-15 seconds later. I created a quick little jQuery hack but it's kinda doing what I want (still not sure if it makes sense to use it tho):

(function($) {
    if (typeof $ !== 'function') return;
    $.longPull = function(args) {
        var opts = $.extend({ method:'GET', onupdate:null, onerror:null, delimiter:'\n', timeout:0}, args || {});
        opts.index = 0;
        var req = $.ajaxSettings.xhr();
        req.open(opts.method, opts.url, true);
        req.timeout = opts.timeout;
        req.onabort = opts.onabort || null;
        req.onerror = opts.onerror || null;
        req.onloadstart = opts.onloadstart || null;
        req.onloadend = opts.onloadend || null;
        req.ontimeout = opts.ontimeout || null;
        req.onprogress = function(e) {
            try {
                var a = new String(e.srcElement.response).split(opts.delimiter);
                for(var i=opts.index; i<a.length; i++) {
                    try {
                        var data = JSON.parse(a[i]); // may not be complete
                        if (typeof opts.onupdate==='function') opts.onupdate(data, i);
                        opts.index = i + 1;
                    } catch(fx){}
                }
            }
            catch(e){}
        };
        req.send(opts.data || null);
    };
})(jQuery);

Largely untested but it seemed to do what you had in mind. I can think of all sorts of ways it could go wrong, though ;-)

$.longPull({ url: 'http://localhost:61873/Test', onupdate: function(data) { console.log(data); }});
3
votes

As requested, here is some pseudo NodeJS code:

function respond_to_client(res,session,cnt)
{
    //context: res is the object we use to respond to the client
    //session: just some info about the client, irrelevant here
    //cnt: initially 0

    //nothing to tell the client, let's long poll.
    if  (nothing_to_send(res,session)) 
    {
        if (cnt<MAX_LONG_POLL_TIME)
        {
            //call this function in 100 ms, increase the counter
            setTimeout(function(){respond_to_client(request_id,res,session,cnt+1)},100);
        }
        else
        {
            close_connection(res); 
            //Counter too high.
            //we have nothing to send and we kept the connection for too long,
            //close it. The client will open another.
        }
    }
    else 
    {
        send_what_we_have(res);
        close_connection(res);
        //the client will consume the data we sent, 
        //then quickly send another request.
    }

    return;

}
2
votes

You don't see how it works from that code only, because the actual difference from a regular request is done on the server.

The Javascript just makes a regular request, but the server doesn't have to respond to the request immediately. If the server doesn't have anything worth returning (i.e. the change that the browser is waiting for hasn't happened yet), the server just waits which keeps the connection open.

If nothing happens on the server for some time, either the client side will time out and make a new request, or the server can choose to return an empty result just to keep the flow going.

1
votes

The connection is not kept open all the time. It is closed automatically when the response is received from the server and server closes the connection. In long polling the server is not supposed to send back data immediately. On ajax complete (when server closes the connection) the new request is sent to the server, which opens a new connection again and starts to keep pending for new response.

As was mentioned, long polling process is handled not only by client side, but mainly by server side. And not only by server script (in case of PHP), but by server itself, which doesn't close the "hanged" connection by timeout.

FWIW, WebSockets use constantly opened connection with the server side, which makes possible to receive and send back the data without closing the connection.

1
votes

I guess no one properly explain why do we need timeout in the code. From jQuery Ajax docs:

Set a timeout (in milliseconds) for the request. This will override any global timeout set with $.ajaxSetup(). The timeout period starts at the point the $.ajax call is made; if several other requests are in progress and the browser has no connections available, it is possible for a request to time out before it can be sent

The timeout option indeed doesn't delay the next execution for X seconds. it only sets a maximum timeout for the current call. Good article about timeout stuff - https://mashupweb.wordpress.com/2013/06/26/you-should-always-add-timeout-to-you-ajax-call-in-jquery/