【问题标题】:callback execution order in jQuery getJSONjQuery getJSON 中的回调执行顺序
【发布时间】:2011-01-31 06:24:45
【问题描述】:

我正在尝试使用小部件实现类似 iGoogle 的仪表板界面,这些小部件使用 JSONP 调用从其他网站获取其内容。

问题在于,如果第一个调用“$.ajax”的小部件需要 8 秒才能取回内容,那么似乎只有在第一个小部件的回调执行后才会调用其他小部件的回调.为了用户体验,如果小部件可以在从远程站点获取内容后立即显示,而不是等待之前安排的那些完成。

有什么办法可以做到吗?

编辑: 我使用 jquery 1.4.1。

我在 Chrome 上进行了测试,但行为似乎与 Firefox 不同。

这是我编写的一个脚本,试图了解发生了什么:

  function showTime(add) { console.log(getTime() + ': ' + add); }
  function getNow() { return new Date().getTime(); }
  initialTime = getNow();
  function getTime() { return getNow() - initialTime; }
  function display(data) {  showTime('received a response'); }

  showTime("Launched a request");
  jQuery.getJSON("http://localhost:51223/WaitXSeconds/3?callback=?", display);
  showTime("Launched a request");
  jQuery.getJSON("http://localhost:51223/WaitXSeconds/4?callback=?", display);
  showTime("Launched a request");
  jQuery.getJSON("http://localhost:63372/WaitXSeconds/9?callback=?", display);
  showTime("Launched a request");
  jQuery.getJSON("http://services.digg.com/stories/top?appkey=http%3A%2F%2Fmashup.com&type=javascript&callback=?", display);
  showTime("Launched a request");
  jQuery.getJSON("http://www.geonames.org/postalCodeLookupJSON?postalcode=10504&country=US&callback=?", display);

前三个调用只是等待指定秒数的假调用。 请注意,我使用两个不同的服务器来实现此方法。

这是 Firefox 3.6.2 控制台中的结果:

0: Launched a request
3: Launched a request
6: Launched a request
11: Launched a request
14: Launched a request
3027: received a response
7096: received a response
9034: received a response
9037: received a response
9039: received a response

.. 这是 Chrome 4.1.249.1036 (41514) 中的结果:

1: Launched a request
2: Launched a request
3: Launched a request
4: Launched a request
5: Launched a request
165: received a response
642: received a response
3145: received a response
7587: received a response
9157: received a response

似乎在 Firefox 中,在所有其他调用都成功之后,对两个公共 API 的两个请求最后被调用。

另一方面,Chrome 会在收到响应后立即执行回调。

在两个浏览器上,当请求发生在同一台服务器上时,它们不会并行完成。他们一个接一个地被安排。但我想这是一个合理的行为。

任何人都可以解释 Firefox 的行为或有任何破解方法来解决这个问题吗?

【问题讨论】:

  • 这听起来不对。调用的执行顺序不应影响它们返回的顺序...
  • 您是否强制这些调用同步?
  • 你用的是什么浏览器?您是否在不同的浏览器中看到相同的行为?
  • @Justin Ethier:我用一个实验更新了这个问题,以证明我的问题。 Firefox 的行为似乎与 Chrome 不同。 @Peter Bailey:我不会强制调用同步。

标签: javascript firefox jquery callback jsonp


【解决方案1】:

在 Firefox 中,如果一个并发 JSONP 请求没有完成,那么所有后续的 JSONP 请求都不会执行,即使它们的响应已经到达并写入这些标签。这是因为 JSONP 使用的

解决方案是通过 iFrame 包装并发 JSONP 请求。有一个名为jquery-jsonp 的项目可以解决这个问题。

这是 iFramed JSONP 的简化版本:

var jsc = (new Date()).getTime();
function sendJsonpRequest(url, data, callback) {
    var iframe = document.createElement("iframe");
    var $iframe = jQuery(iframe);
    $iframe.css("display", "none");
    jQuery("head").append($iframe);

    var iframeWindow = iframe.contentWindow;
    var iframeDocument = iframeWindow.document;

    iframeDocument.open();
    iframeDocument.write("<html><head></head><body></body></html>");
    iframeDocument.close();

    var jsonp = "jsonp" + jsc++;
    var url = url + "?callback=" + jsonp;
    var params = jQuery.param(data);
    if (params) {
        url += "&" + params;
    }

    // Handle JSONP-style loading
    iframeWindow[jsonp] = function(data){
        if (callback) {
            callback(data);
        }
        // Garbage collect
        iframeWindow[jsonp] = undefined;
        try{ delete iframeWindow[jsonp]; } catch(e){}
        if (head) {
            head.removeChild(script);
        }
        $iframe.remove();
    };

    var head = iframeDocument.getElementsByTagName("head")[0];
    var script = iframeDocument.createElement("script");
    script.src = url;

    head.appendChild(script);
}

【讨论】:

  • 很好的答案!我已经切换到 jquery-jsonp,现在它就像一个魅力。很高兴知道发生了什么。谢谢。
  • 我想在这里添加一些注释。我看到有些人写道 jQuery.ajax() 应该是异步的。好吧,只要我们谈论 AJAX,他们就是对的。但是 jQuery.ajax({dataType:"script"}) 或 jQuery.ajax({dataType:"jsonp"}) 或 jQuery.getScript() 或 jQuery.getJSON with callback=?参数,这些方法不是AJAX方法,而是
【解决方案2】:

根据jQuery.ajax()页面:

Ajax 中的第一个字母代表“异步”,意思是操作并行进行,不保证完成的顺序。

我不知道为什么后者调用的小部件稍后会返回,但我认为这与 jQuery 调用无关,除非按照 Peter 的建议,您已将 async 明确设置为 false .

【讨论】:

    【解决方案3】:

    默认$.ajax is asynchronous

    asyncBoolean 默认值:true

    确保您没有将其设置为 false。使用Firebug 调试 XHR 请求以查看请求是否正确发送以及 dom 未更新的原因。

    您可以查看Tutorial,了解如何使用这些工具以及如何发现您的 GUI 出了什么问题。

    【讨论】:

      猜你喜欢
      • 2011-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-24
      • 2015-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多