Как последовательно пройти вызовы GET/POST (в ожидании предыдущего) возврата?

Я пишу скрипт Tampermonkey для веб-страницы и пытаюсь извлечь данные из других страниц.
Я пытаюсь сделать функцию, внутри которой есть цикл, который проходит через список, llcListи получает данные из ajax-метода GET, но хотел бы дождаться завершения одного запроса, прежде чем перейти ко второму.
Бонус был бы, если бы я мог подождать немного больше времени.

Что должно произойти:

  1. отправить запрос на получение списка товаров [0]
  2. получить возврат данных, обработать их
  3. подожди немного
  4. отправить новый запрос на получение списка товаров [1]

Это возможно? Я пробовал несколько методов, каждый цикл времени отправлять все запросы с точностью до секунды.:

function F_Company_LLC(){
for (i = 0; i < llcList.length;i++) {
        if(llcList[i][2]=="lab"){
            //run function 0
            //break;
        }
        else if(llcList[i][2]=="shop"){
            //run function 1
            //break;
        }
        else{
            F_GET_CompData(llcList, llcList[i][1],i,function(result){
                console.log(result);
            });
        }
}}

function F_GET_CompData(F_GET_CompData_list, CompID, F_GET_CompData_row, callback){
$.ajax({
    method : "GET",
    url: base_link+"/company/edit_company/"+CompID,
    beforeSend: function(){runningRequest++;},
    success: function(data){

  //data processing

        runningRequest--;
    },
    error: function() {console.log("Get_ComData");}
});
callback(runningRequest);}

2 ответа

Решение

Это распространенный сценарий. Обратите внимание, что зачастую нет необходимости обрабатывать вызовы последовательно. Как правило, достаточно просто отправить контекст с помощью вызовов ajax и собрать все воедино, как показано в полу-случайном порядке, как показано в этом ответе.


Одним из способов принудительного последовательного поведения является цепочка вызовов через complete функция. Вот полностью функциональный код, который демонстрирует процесс. Чтобы использовать его, вставьте его в консоль браузера на странице переполнения стека.:

var listO_pages = ["q/48/", "q/27/", "q/34/", "q/69/", "badpage"];
var numPages    = listO_pages.length;

getPageN (0);  //-- Kick off chained fetches

function getPageN (K) {
    if (K >= 0  &&  K < numPages) {
        let targPage = listO_pages[K];

        $.ajax ( {
            url:            "https://stackru.com/" + targPage,
            context:        {arryIdx: K},  //  Object Helps handle K==0, and other things
            success:        processPage,
            complete:       finishUpRequest,
            error:          logError
        } );
    }
}

function processPage (sData, sStatus, jqXHR) {
    //-- Use DOMParser so that images and scripts don't get loaded (like jQuery methods would).
    var parser          = new DOMParser ();
    var doc             = parser.parseFromString (sData, "text/html");
    var payloadTable    = doc.querySelector ("title");
    var pageTitle       = "Not found!";
    if (payloadTable) {
        pageTitle       = payloadTable.textContent.trim ();
    }
    var [tIdx, tPage]   = getIdxAndPage (this);  // Set by `context` property

    console.log (`Processed index ${tIdx} (${tPage}). Its title was: "${pageTitle}"`);
}

function finishUpRequest (jqXHR, txtStatus) {
    var nextIdx     = this.arryIdx + 1;
    if (nextIdx < numPages) {
        var tPage   = listO_pages[nextIdx];
        //-- The setTimeout is seldom needed, but added here per OP's request.
        setTimeout ( function () {
            console.log (`Fetching index ${nextIdx} (${tPage})...`);
            getPageN (nextIdx);
        }, 222);
    }
}

function logError (jqXHR, txtStatus, txtError) {
    var [tIdx, tPage]   = getIdxAndPage (this);  // Set by `context` property
    console.error (`Oopsie at index ${tIdx} (${tPage})!`, txtStatus, txtError, jqXHR);
}

function getIdxAndPage (contextThis) {
    return [contextThis.arryIdx, listO_pages[contextThis.arryIdx] ];
}


Это обычно выводит:

Обработанный индекс 0 (q/48/). Его заголовок был: "Несколько кнопок отправки в форме HTML - Переполнение стека"
Выборка индекса 1 (q/27/)...
Обработанный индекс 1 (q / 27 /). Его название было: "datetime - Рассчитать относительное время в C# - Переполнение стека"
Индекс выборки 2 (q/34/)...
Обработанный индекс 2 (q / 34 /). Его название было: "flex - выгрузка ByteArray в Actionscript 3 - переполнение стека"
Индекс выборки 3 (q/69/)...
Обработанный индекс 3 (q / 69 /). Его название было: ".net - Как рассчитать чей-то возраст в C#? - Переполнение стека"
Извлечение индекса 4 (плохая страница)...
ПОЛУЧИТЬ https://stackru.com/badpage?_=1512087299126 404 ()
Упс в индексе 4 (badpage)! объект ошибки {...

- в зависимости от вашей репутации переполнения стека.


Важно: не пытайтесь использовать async: false методы. Они просто: заблокируют ваш браузер, иногда приводят к сбоям в работе компьютера и значительно усложняют отладку и частичные результаты.

Имитация цикла for с асинхронными запросами ajax. На Аяксе complete callback перейти к следующему пункту в списке:

function F_Company_LLC(llcList) {
    var i= 0;

    function getNext() {

           if(llcList[i][2]=="lab"){
                //run function 0

                    ++i;

                    getNext();
            }
            else if(llcList[i][2]=="shop"){
                //run function 1

                    ++i;

                    getNext();
            }
            else{

             $.ajax({

              url: base_link+"/company/edit_company/"+llcList[i][1], //CompID
              method: 'GET',
              async: true,
              success: function(data) {
                if (data.status == "success" && i <= llcList.length) {
                     //data processing
                 }
               },
               error: function(xhr) { 
                alert("Error while processing CompID: " + llcList[i][1]);

               },
              complete: function() {
             //complete executes after either 
             //the success or error callback were executed.
                     ++i;
                    getNext();//go to next item in the list
              },
             });      
            }  
    }

    getNext();
}


F_Company_LLC(llcList);
Другие вопросы по тегам