Как получить AJAX-запрос на ожидание отображения страницы перед возвратом ответа?

Я нахожусь в процессе написания скрипта Greasemonkey для страниц на этом сайте (Site1). У Site1 есть предложения и предложения различного рода, и мой сценарий GM стремится сделать следующее:

Когда кто-то посещает предложение на Сайте 1, сценарий запрашивает Сайт 2, чтобы выяснить, указан ли этот отель на Сайте 2. Если это так, отобразите результаты поиска с сайта 2 на сайте 1.

Проблема в том, что Site2 отображает индикатор выполнения ("Загрузка результатов"), а затем отображает результаты. Таким образом, мой Ajax-запрос всегда возвращает пустые результаты и выглядит следующим образом (см. Раздел в красной рамке):
(Нажмите для увеличения изображения) незаконченные результаты


Однако на самом деле он должен иметь полное содержание результатов поиска с Site2, например:
(Нажмите для увеличения изображения) готовые результаты


Я пробовал синхронный запрос Ajax, а также GM_xmlhttpRequest но безрезультатно.

Это проблемный индикатор выполнения на сайте 2:
(Нажмите для увеличения изображения) статус бар


Как я могу получить AJAX-запрос, чтобы дождаться, пока поиск на Site2 будет полностью обработан, прежде чем возвращать ответ на Site1?

Для справки, мой полный рабочий код скрипта находится на pastebin.com.

Это соответствующий фрагмент:

$(document).ready(function(){   
var rewardsSiteResults = $('<div class="panel deal-panel rc-lr"></div>').attr('id', "rewardsSiteResults")
        .html("<p>" + progressMessageText + "</p> ").append(spinnerGif);
$(insertSelector).after(rewardsSiteResults);

var addressMap = getAddressOfHotel();
var pinCode = addressMap[pinCodePlaceHolder];
var hotelName = addressMap[hotelNamePlaceHolder];
var queryURL = constructQueryURL(pinCode, hotelName);

$.ajaxSetup({async:true, timeout: 5000});
$.get(queryURL,null, function(response) {
    if(!displayed){
        displayed=true;
        //rewardsSiteResults.html("adfaasddsf");
        var text = $(response).find("#col2");
        $(text).find("script").remove();

        //console.log(text.html())
//          $('<iframe id="someId"/>').appendTo('#rewardsSiteResults')
//          .contents().find('body').append(response);
        rewardsSiteResults.html("<div class='panel deal-panel rc-lr'>" + text.html() +"</div>");
        //console.log(response);
    }
},'html');  
});

1 ответ

Решение

Для того, чтобы AJAX мог "подождать, пока страница будет отрисована", ему фактически придется полностью обработать страницу, извлечь и запустить все включенные файлы CSS и javascript. Это не легко и не рекомендуется. К счастью, вам все равно не нужно этого делать.

Вот три лучших способа решения этой проблемы:

  1. Страница ресурса (mpdining.rewardsnetwork.com, для этого вопроса) может иметь API. Если это так, найдите его и используйте. Это ваша лучшая ставка, если она доступна.

  2. Проанализируйте javascript и / или AJAX-запросы страницы ресурса. использование GM_xmlhttpRequest() напрямую получать только данные полезной нагрузки, вместо того, чтобы пытаться проанализировать страницу ресурса.

    Иногда этот процесс довольно прост, но некоторые сайты требуют сложного взаимодействия и / или аутентификации.

  3. Загрузите страницу ресурса в скрытый iframe; настройте сценарий Greasemonkey для запуска как на странице ресурсов, так и на главной странице, а также для передачи нужных данных с помощью postMessage(),

    Этот подход почти всегда работает, хотя вам, возможно, придется помешать некоторым страницам попытаться "вырваться" из iframe.



Использование скрытого фрейма для получения данных из междоменной страницы ресурсов:

Скрипты Greasemonkey будут запускаться как на обычной странице, так и на страницах внутри фреймов. Фактически, вы можете установить один и тот же скрипт для запуска как на нескольких доменах, так и на нескольких.

Если на главной странице и на странице ресурса iframed выполняются сценарии GM, экземпляры сценариев могут связываться друг с другом через междоменный домен, используя postMessage(),

Например, предположим, что у нас есть сайт http://fiddle.jshell.net/9ttvF/show/, который содержит данные о поездках, и мы хотим объединить этот сайт с соответствующими данными с ресурса сайта http://jsbin.com/ahacab, который использует AJAX чтобы получить данные полезной нагрузки.

Целевой (основной) сайт выглядит так:
целевой сайт

Ресурс сайта на первый взгляд выглядит так:
ресурс сайта, старт

Затем заканчивается так: ресурс сайта, финиш


Следующий скрипт:

  1. Загружает страницу ресурса в скрытом фрейме.
  2. Запускает второй экземпляр на странице iframed.
  3. Ожидание завершения страницы iframed, обработка результатов по желанию.
  4. Отправляет нужные данные полезной нагрузки в сценарий GM, выполняющийся на целевой (главной) странице.
  5. Затем скрипт целевой страницы вставляет данные полезной нагрузки для завершения смешивания.
// ==UserScript==
// @name     _Cross-site, AJAX scrape demo
// @include  http://fiddle.jshell.net/9ttvF/show/
// @include  http://jsbin.com/ahacab*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant    GM_addStyle
// ==/UserScript==

if (/fiddle\.jshell\.net/i.test (location.host) ) {
    console.log ("***Master-page start...");

    /*--- Inform the user.
    */
    $("#plainResults").before (
        '<div id="gmFetchRez">Greasemonkey is fetching results from jsbin.com...</div>'
    );

    /*--- Setup to process messages from the GM instance running on the iFrame:
    */
    window.addEventListener ("message", receiveMessage, false);

    /*--- Load the resource site in a hidden iframe.
    */
    $("body").append ('<iframe src="http://jsbin.com/ahacab" id="gmIframe"></iframe>');
}
else {
    console.log ("***Framed start...");
    /*--- Wait for the AJAXed-in content...
    */
    waitForKeyElements ("#results table.rezTable", sendResourcePageData);
}

function sendResourcePageData (jNode) {
    console.log ("Results found!  Sending them to the main window...");

    window.top.postMessage (jNode.html(), "*");
}

function receiveMessage (event) {
    if (event.origin != "http://jsbin.com")     return;

    $("#gmFetchRez").html (event.data);
}

//--- Use CSS to control appearances.
GM_addStyle ( "                                 \
    #gmIframe {                                 \
        display:            none;               \
    }                                           \
    #gmFetchRez {                               \
        background:         lightYellow;        \
        border:             3px double red;     \
        padding:            1em;                \
    }                                           \
" );

Окончательный результат выглядит следующим образом: скрипт установлен и запущен: результат mashup

Другие вопросы по тегам