jQuery getJSON中的回调执行顺序

时间:2010-03-24 13:29:30

标签: javascript firefox jquery callback jsonp

我正在尝试使用小部件来实现类似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的行为,还是有任何黑客可以解决这个问题?

3 个答案:

答案 0 :(得分:2)

根据jQuery.ajax()页面:

  

Ajax中的第一个字母代表“异步”,意味着操作并行发生,并且无法保证完成顺序。

我不知道为什么后面称为小部件后来会返回,但我不认为这与jQuery调用有关,除非像Peter建议的那样,你明确地将async设置为{ {1}}。

答案 1 :(得分:2)

在Firefox中,如果并发JSONP请求之一未完成,则即使其响应已到达并写入这些标记,也不会执行所有连续的JSONP请求。这是因为< script> JSONP使用的标记在Firefox中同步执行。因此,如果一个< script>没有完成,连续< script>标签不会被执行,即使它们填充了响应数据。

解决方案是通过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);
}

答案 2 :(得分:1)

默认情况下$.ajax is asynchronous

  

asyncBoolean默认值:true

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

您可以查看此Tutorial,了解如何使用这些工具以及如何发现GUI的错误。