jQuery getJSON 中的回调执行顺序

发布于 2024-08-26 12:49:44 字数 2133 浏览 5 评论 0原文

我正在尝试使用小部件实现类似 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 的行为或者有什么办法可以解决这个问题吗?

I'm trying to implement a iGoogle like dashboard interface using widgets that get their content from other sites using JSONP calls.

The problem is that if the first widget that calls the "$.ajax" takes 8 seconds to get the content back, it seems that the callbacks of the other widgets will only be called after the callback of the first widget gets executed. For the user experience, it would be better if the widgets could be displayed as soon as they get the content back from the remote sites, and not wait for those that were scheduled before to complete.

Is there a way I can do that?

EDIT :
I use jquery 1.4.1.

I tested on Chrome and the behaviour seems to be different than on Firefox.

Here is a script that I've made up to try to get what happens :

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

The first three calls are just fake calls that wait the specified number of seconds.
Note that I use two different servers implementing this method.

Here is the result in the console on 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

.. and here is the result in 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

It seems that in Firefox, the two requests to the two public APIs get called at the end, after all the other calls succeed.

Chrome, on the other hand, manages to execute the callback as soon as it receives the response.

On both browsers, when the request happen on the same server, they are not done in parallel. They are scheduled one after the other. But I guess this is a reasonable behaviour.

Can anybody explain Firefox's behaviour or has any hack to go around this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

二手情话 2024-09-02 12:49:44

在 Firefox 中,如果其中一个并发 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);
}

In Firefox, if one of concurrent JSONP request isn't finished, then all successive JSONP request aren't executed, even if their responses have already arrived and written into these tags. This is because <script> tags, used by JSONP, executed synchronously in Firefox. So if one <script> isn't finished, successive <script> tags aren't executed, even if they are populated with response data.

The solution is to wrap concurrent JSONP requests by iFrame. There is a project called jquery-jsonp that solves this issue.

Here is a simplified version of 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);
}
傾旎 2024-09-02 12:49:44

根据 jQuery.ajax() 页面:

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

我不知道为什么后者称为小部件稍后返回,但我不认为这与 jQuery 调用有关,除非,正如 Peter 建议的那样,您已将 async 显式设置为 <代码>假。

According to the jQuery.ajax() page:

The first letter in Ajax stands for "asynchronous," meaning that the operation occurs in parallel and the order of completion is not guaranteed.

I don't know why the latter-called widgets are returning later, but I don't think it's to do with the jQuery call, unless, as Peter suggested, you've explicitly set async to false.

染火枫林 2024-09-02 12:49:44

默认情况下 $.ajax 是异步的

asyncBoolean 默认值:true

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

你可以看看这个 教程了解如何使用这些工具以及如何发现 GUI 的问题。

By default $.ajax is asynchronous.

asyncBoolean Default: true

Make sure you don't have it set to false. Debug the XHR requests using Firebug to see if the requests are correctly sent and why the dom is not getting updated.

You could have a look at this Tutorial to see how to use these tools and how to discover what's wrong with your GUI.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文