порядок выполнения обратного вызова в jQuery getJSON - PullRequest
0 голосов
/ 24 марта 2010

Я пытаюсь реализовать интерфейс панели управления, похожий на 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 ]

2 голосов
/ 18 мая 2010

В Firefox, если один из одновременных запросов JSONP не завершен, все последующие запросы JSONP не выполняются, даже если их ответы уже получены и записаны в эти теги. Это связано с тем, что теги , используемые JSONP, выполняются синхронно в Firefox. Поэтому, если один не завершен, последовательные теги не выполняются, даже если они заполнены данными ответов.

Решение - обернуть параллельные запросы JSONP от iFrame. Существует проект под названием 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 голосов
/ 24 марта 2010

По данным jQuery.ajax () Страница:

Первая буква в Ajax обозначает «асинхронный», что означает, что операция происходит параллельно и порядок выполнения не гарантируется.

Я не знаю, почему последние вызванные виджеты возвращаются позже, но я не думаю, что это связано с вызовом jQuery, если, как предположил Питер, вы явно не установили async в false .

1 голос
/ 24 марта 2010

По умолчанию $. Ajax является асинхронным .

asyncBoolean По умолчанию: true

Убедитесь, что для него не установлено значение false. Отладьте XHR-запросы, используя Firebug , чтобы увидеть, правильно ли отправляются запросы и почему dom не обновляется.

Вы можете взглянуть на это Учебное пособие , чтобы узнать, как использовать эти инструменты и как обнаружить, что не так с вашим графическим интерфейсом.

...