jQuery,简单轮询示例

114

我正在学习jQuery,想找一个简单的代码示例,用于轮询API以便满足某个条件。(例如,每隔几秒钟请求一个网页并处理结果)

我已经熟悉了在jQuery中如何执行AJAX,但似乎找不到在“定时器”上执行AJAX的“正确”方法。

9个回答

155
function doPoll(){
    $.post('ajax/test.html', function(data) {
        alert(data);  // process results here
        setTimeout(doPoll,5000);
    });
}

4
为什么有些人使用setTimeout,有些人使用setInterval?它们之间有什么不同和优劣势? - Mike
39
setInterval会每5秒钟调用一个ajax请求,不管之前的请求是否已经完成。但是,作者认为更好的做法是,在等待上一个ajax请求的结果后再延迟5秒钟发起下一个请求。虽然有时会使用setInterval,但这并不是其中之一。在上一个请求的结果还未返回之前,我们不应该发起任何新的请求。 - Johnny Craig
117
需要注意的是,建议的代码会在单个请求失败时停止轮询。在典型情况下,您可能仍希望继续轮询。我建议不要在成功处理程序中使用setTimeout,而是使用jQuery always链接ajax调用。如下所示:`$.post('ajax/test.html') .done(function(data) { /* 处理数据 */ }) .always(function() { setTimeout(doPoll, 5000); });` - Mårten Wikström
6
没有尾调用优化,这会导致函数调用栈不断增长。建议使用跳板模式(trampoline pattern)。 - Boopathi Rajaa
8
请提供一个这样的蹦床模式示例,@BoopathiRajaa。 - santa
显示剩余5条评论

68

这是一篇(archive.org镜像的)关于使用jQuery进行长轮询(长时间持有HTTP请求)的有用文章。以下代码片段源自该文章:

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

这将使下一次请求仅在ajax请求完成后执行。

与上面的变体不同,它会在第一次调用时立即执行,然后才遵守等待/超时间隔。

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

有没有一种方法可以取消轮询或发送信号来停止它? - Tal
如果从服务器获得了预期结果,我该如何清除超时? - abhishek77in
1
您可以像以下示例一样清除超时:```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("结束轮询"); window.clearTimeout(timeout); } })();``` - Marius
5
请不要点击上面的techoctave.com链接。它试图执行各种危险操作。 - Siddharth Ram

14
从 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);
  • 不使用递归(函数堆栈不受影响)。
  • 在需要尾调用优化的setTimeout递归中不受影响。

1
很高兴看到一个ES6的解决方案! - PHearst
什么使得 Boopathi Rajaa 的 setInterval() 成为 ES6 解决方案? - Halil

11
function poll(){
    $("ajax.php", function(data){
        //do stuff  
    }); 
}

setInterval(function(){ poll(); }, 5000);

4
请注意:您可以使用此语法 setInterval(poll, 5000); - R3tep

7
function make_call()
{
  // do the request

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

$(document).ready(function() {
  make_call();
});

2

jQuery.Deferred()可以简化异步顺序和错误处理的管理。

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
    }

这是一种优雅的方法,但还有一些需要注意的地方...

  • 如果你不想让then()立即执行下去,回调函数应该返回另一个thenable对象(可能是另一个Deferred),睡眠和ajax代码行都是这样做的。
  • 其他的太尴尬了,不好意思说出来。 :)

类似的答案在:while循环中的延迟 - Brent Bradburn
我的“迭代递归”注释可能有点误导性。 这里实际上不存在递归,因为“递归”调用发生在匿名回调函数中——在 initiate_polling 运行完成之后。 - Brent Bradburn
在最新的浏览器中,您不再需要使用jQuery来完成此操作 - 请参见我的答案:https://dev59.com/UVYM5IYBdhLWcg3whAeH#48728503 - Brent Bradburn
纯JavaScript超时: new Promise(resolve => setTimeout(resolve,1000))。then(()=> alert(“完成”)) - Brent Bradburn
异步递归就是迭代。 - Brent Bradburn

2
这个解决方案:
  1. 具有超时功能
  2. 即使在错误响应后也可进行轮询操作
jQuery 的最低版本为 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()
})

1
我为此创建了一个小的 JQuery 插件。你可以尝试使用它:
$.poll('http://my/url', 100, (xhr, status, data) => {
    return data.hello === 'world';
})

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


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);
})();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接