114

I'm learning jQuery, and I'm trying to find a simple code example that will poll an API for a condition. (ie, request a webpage every few seconds and process the results)

I'm familiar with how to do AJAX in jQuery, I just can't seem to find the "proper" way of getting it to execute on a "timer".

Mike
  • 58,961
  • 76
  • 175
  • 221

9 Answers9

155
function doPoll(){
    $.post('ajax/test.html', function(data) {
        alert(data);  // process results here
        setTimeout(doPoll,5000);
    });
}
Johnny Craig
  • 4,974
  • 2
  • 26
  • 27
  • 4
    some people have used `setTimeout` and some have used `setInterval`. Why would one be preferred to another? – Mike Jul 26 '11 at 21:40
  • 39
    setinterval would make an ajax call every 5 seconds no matter what. the way have written it (which i believe is good practice) will wait for the results THEN make another ajax request 5 seconds later. there are times i would use setinterval, but this is not one of them. we should not be making any new requests until we get the results from the last request – Johnny Craig Jul 26 '11 at 21:47
  • 117
    Please beware though that the suggested code will stop polling if a single request fails. In a typical scenario you would probably want to continue polling anyway. I would not have `setTimeout` within the *success handler* but instead chain the ajax call with [jQuery always](http://api.jquery.com/deferred.always/). Like this: `$.post('ajax/test.html') .done(function(data) { /* process */ }) .always(function() { setTimeout(doPoll, 5000); });` – Mårten Wikström May 06 '13 at 19:21
  • When I had an input parameter to my doPoll function like `setTimeout(doPoll(id), 5000);` the call had to be wrapped in a function in order to work. `setTimeout(function() {doPoll(id); }, 5000);` – David Jan 28 '14 at 12:47
  • 6
    There is no tail call optimization. This would just keep increasing the function call stack. Usage of trampoline pattern is recommended. – Boopathi Rajaa Jan 20 '15 at 21:33
  • 8
    @BoopathiRajaa please provide an example of such trampoline pattern. – santa Aug 25 '15 at 16:04
  • @BoopathiRajaa apparently, the trampoline pattern does not improve performance. It just allows the computer to keep going after recursion would have reached the limit of the stack. Unless I'm mistaken this seems like it would actually hide memory leaks. – MCB Jun 04 '16 at 03:47
  • 2
    But isn't the fact that your polling is going to be limited by the stack size a reason enough that it's bad to use recursion? – jwrush Aug 31 '16 at 20:32
  • 4
    Call stack limits on current browsers are so high that this should not be anyone's concern. iE has the lowest limit and you could still poll your server every five seconds for over 24 hours without having to refresh the page. If that's not enough then polling is not the solution to your needs. – Johnny Craig Sep 02 '16 at 03:33
  • @BoopathiRajaa: There is no recursion here -- just a series of event-triggered callbacks. A debugger might attempt to track the indefinite (and cyclical) chain of asynchronous events, but that wouldn't affect the actual call stack. – Brent Bradburn Feb 11 '18 at 06:22
68

Here's a (archive.org mirror of a) helpful article on long polling (long-held HTTP request) using jQuery. A code snippet derived from this article:

(function poll() {
    setTimeout(function() {
        $.ajax({
            url: "/server/api/function",
            type: "GET",
            success: function(data) {
                console.log("polling");
            },
            dataType: "json",
            complete: poll,
            timeout: 2000
        })
    }, 5000);
})();

This will make the next request only after the ajax request has completed.

A variation on the above that will execute immediately the first time it is called before honouring the wait/timeout interval.

(function poll() {
    $.ajax({
        url: "/server/api/function",
        type: "GET",
        success: function(data) {
            console.log("polling");
        },
        dataType: "json",
        complete: setTimeout(function() {poll()}, 5000),
        timeout: 2000
    })
})();
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
chrisjleu
  • 4,329
  • 7
  • 42
  • 55
  • Is there a way to cancel polling, or signal it to stop? – Tal Mar 31 '18 at 01:58
  • How do I clear timeout if expected result is obtained from the server? – abhishek77in Oct 17 '18 at 16:18
  • 1
    You can clear timeout like in these example: ```let is_success = false; (function poll() { let timeout = setTimeout(function() { $.ajax({ url: resp.location, type: "GET", success: function(data) { if(YOUR_CONDITION) { is_success=true; } }, dataType: "json", complete: poll, timeout: 2000 }) }, 5000); if(is_success) { console.log("ending poll"); window.clearTimeout(timeout); } })();``` – Marius Nov 11 '19 at 16:59
  • 5
    Do not click on the techoctave.com link above. Tries to do all kinds of nasty things – Siddharth Ram Jun 26 '20 at 16:23
14

From ES6,

var co = require('co');
var $ = require('jQuery');

// because jquery doesn't support Promises/A+ spec
function ajax(opts) {
  return new Promise(function(resolve, reject) {
    $.extend(opts, {
      success: resolve,
      error: reject
    });
    $.ajax(opts);
  }
}

var poll = function() {
  co(function *() {
    return yield ajax({
      url: '/my-api',
      type: 'json',
      method: 'post'
    });
  }).then(function(response) {
    console.log(response);
  }).catch(function(err) {
    console.log(err);
  });
};

setInterval(poll, 5000);
  • Doesn't use recursion (function stack is not affected).
  • Doesn't suffer where setTimeout-recursion needs to be tail-call optimized.
Boopathi Rajaa
  • 4,659
  • 2
  • 31
  • 53
11
function poll(){
    $("ajax.php", function(data){
        //do stuff  
    }); 
}

setInterval(function(){ poll(); }, 5000);
genesis
  • 50,477
  • 20
  • 96
  • 125
7
function make_call()
{
  // do the request

  setTimeout(function(){ 
    make_call();
  }, 5000);
}

$(document).ready(function() {
  make_call();
});
PeeHaa
  • 71,436
  • 58
  • 190
  • 262
2

jQuery.Deferred() can simplify management of asynchronous sequencing and error handling.

polling_active = true // set false to interrupt polling

function initiate_polling()
    {
    $.Deferred().resolve() // optional boilerplate providing the initial 'then()'
    .then( () => $.Deferred( d=>setTimeout(()=>d.resolve(),5000) ) ) // sleep
    .then( () => $.get('/my-api') ) // initiate AJAX
    .then( response =>
        {
        if ( JSON.parse(response).my_result == my_target ) polling_active = false
        if ( ...unhappy... ) return $.Deferred().reject("unhappy") // abort
        if ( polling_active ) initiate_polling() // iterative recursion
        })
    .fail( r => { polling_active=false, alert('failed: '+r) } ) // report errors
    }

This is an elegant approach, but there are some gotchas...

  • If you don't want a then() to fall through immediately, the callback should return another thenable object (probably another Deferred), which the sleep and ajax lines both do.
  • The others are too embarrassing to admit. :)
Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
2

This solution:

  1. has timeout
  2. polling works also after error response

Minimum version of jQuery is 1.12

$(document).ready(function () {
  function poll () {
    $.get({
      url: '/api/stream/',
      success: function (data) {
        console.log(data)
      },
      timeout: 10000                    // == 10 seconds timeout
    }).always(function () {
      setTimeout(poll, 30000)           // == 30 seconds polling period
    })
  }

  // start polling
  poll()
})
jozo
  • 4,232
  • 1
  • 27
  • 29
1

I created a tiny JQuery plugin for this. You may try it:

$.poll('http://my/url', 100, (xhr, status, data) => {
    return data.hello === 'world';
})

https://www.npmjs.com/package/jquerypoll

Sohan
  • 3,757
  • 2
  • 24
  • 24
0
(function poll() {
    setTimeout(function() {
        //
        var search = {}
        search["ssn"] = "831-33-6049";
        search["first"] = "Harve";
        search["last"] = "Veum";
        search["gender"] = "M";
        search["street"] = "5017 Ottis Tunnel Apt. 176";
        search["city"] = "Shamrock";
        search["state"] = "OK";
        search["zip"] = "74068";
        search["lat"] = "35.9124";
        search["long"] = "-96.578";
        search["city_pop"] = "111";
        search["job"] = "Higher education careers adviser";
        search["dob"] = "1995-08-14";
        search["acct_num"] = "11220423";
        search["profile"] = "millenials.json";
        search["transnum"] = "9999999";
        search["transdate"] = $("#datepicker").val();
        search["category"] = $("#category").val();
        search["amt"] = $("#amt").val();
        search["row_key"] = "831-33-6049_9999999";



        $.ajax({
            type : "POST",
            headers : {
                contentType : "application/json"
            },
            contentType : "application/json",
            url : "/stream_more",
            data : JSON.stringify(search),
            dataType : 'json',
            complete : poll,
            cache : false,
            timeout : 600000,
            success : function(data) {
                //
                //alert('jax')
                console.log("SUCCESS : ", data);
                //$("#btn-search").prop("disabled", false);
                // $('#feedback').html("");
                for (var i = 0; i < data.length; i++) {
                    //
                    $('#feedback').prepend(
                            '<tr><td>' + data[i].ssn + '</td><td>'
                                    + data[i].transdate + '</td><td>'
                                    + data[i].category + '</td><td>'
                                    + data[i].amt + '</td><td>'
                                    + data[i].purch_prob + '</td><td>'
                                    + data[i].offer + '</td></tr>').html();
                }

            },
            error : function(e) {
                //alert("error" + e);

                var json = "<h4>Ajax Response</h4><pre>" + e.responseText
                        + "</pre>";
                $('#feedback').html(json);

                console.log("ERROR : ", e);
                $("#btn-search").prop("disabled", false);

            }
        });

    }, 3000);
})();
vaquar khan
  • 10,864
  • 5
  • 72
  • 96