jQuery, simple polling example
Asked Answered
P

9

115

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".

Pneumo answered 26/7, 2011 at 19:59 Comment(0)
J
155
function doPoll(){
    $.post('ajax/test.html', function(data) {
        alert(data);  // process results here
        setTimeout(doPoll,5000);
    });
}
Jelle answered 26/7, 2011 at 20:2 Comment(10)
some people have used setTimeout and some have used setInterval. Why would one be preferred to another?Pneumo
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 requestJelle
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. Like this: $.post('ajax/test.html') .done(function(data) { /* process */ }) .always(function() { setTimeout(doPoll, 5000); });Propane
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);Lordship
There is no tail call optimization. This would just keep increasing the function call stack. Usage of trampoline pattern is recommended.Chancemedley
@BoopathiRajaa please provide an example of such trampoline pattern.Carltoncarly
@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.Aleman
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?Soften
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.Jelle
@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.Lecture
H
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
    })
})();
Hyacinthe answered 27/6, 2012 at 8:2 Comment(4)
Is there a way to cancel polling, or signal it to stop?Alphosis
How do I clear timeout if expected result is obtained from the server?Delius
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); } })();Lyndel
Do not click on the techoctave.com link above. Tries to do all kinds of nasty thingsGenovera
C
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.
Chancemedley answered 20/1, 2015 at 21:58 Comment(2)
Nice to see an ES6 solution!Horatius
What makes it an ES6 solution Boopathi Rajaa, setInterval()?Babism
S
11
function poll(){
    $("ajax.php", function(data){
        //do stuff  
    }); 
}

setInterval(function(){ poll(); }, 5000);
Sicilia answered 26/7, 2011 at 20:2 Comment(1)
Note : You can use this syntax setInterval(poll, 5000);Accroach
S
7
function make_call()
{
  // do the request

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

$(document).ready(function() {
  make_call();
});
Sadoff answered 26/7, 2011 at 20:2 Comment(0)
L
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. :)
Lecture answered 14/1, 2018 at 17:24 Comment(5)
Similar answers at: Deferred in a while loopLecture
My "iterative recursion" comment might be a bit misleading. There is no actual recursion here since the "recursive" call occurs from an anonymous callback -- after initiate_polling has run to completion.Lecture
In the latest browsers, you no longer need jQuery do do this -- see my answer here: https://mcmap.net/q/189643/-how-do-i-fix-cors-issue-in-fetch-apiLecture
Pure JavaScript timeout: new Promise( resolve => setTimeout(resolve,1000) ).then( () => alert("done") )Lecture
Async Recursion Is IterationLecture
D
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()
})
Due answered 24/4, 2020 at 16:11 Comment(0)
P
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

Philine answered 12/8, 2019 at 19:36 Comment(0)
E
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);
})();
Elaterin answered 22/5, 2018 at 18:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.