2016-11-13 2 views
1

Добрый день, ребята -

Есть ли известный способ проверить, завершен ли звонок $.ajax?

- НАПРИМЕР -

Допустим, я использую $.ajax вызов для загрузки в большом количестве листовки многоугольников из .geojson файла (асинхронно в качестве слоя группы). В нормальных условиях это происходит почти сразу, но пользователь решил на этот раз загрузить большую работу. Пользователь предположил, что набор полигонов был загружен и пытается сделать что-то с этой группой слоев преждевременно - только чтобы найти, что ничего не происходит (группа слоев на самом деле еще не существует в браузере).

Моя интуиция (я новичок в веб-разработке) должен иметь определенный глобальный флаг, установленный для зависимого алгоритма проверки. Мы должны установить флаг перед загрузкой слоев, а затем изменить его на какое-то другое значение в разделе .done({}) вызова $.ajax.

- ОБНОВЛЕНИЕ -

Я переработан код, чтобы позволить пользователям выбирать, хотят ли они повторить запрос, а также заставить браузер подождать некоторое время перед повтором запроса.

Однако, я также обнаружил, что проблема связана с Chrome. Кажется, что Firefox способен обрабатывать обратный вызов $ .ajax.always, как только он заканчивается (другими словами, обратный вызов $ .ajax.always прервет регулярный поток javascript).

Chrome, похоже, блокирует обратный вызов $ .ajax.always и разрешает его выполнение только после того, как все остальные javascript завершили работу (без прерывания).

Этот конкретный вопрос связан с отладочным случаем, когда автоматизированный пользовательский ввод из цикла - и поскольку Chrome не вызывает обратный вызов $ .ajax.always, пока текущий процесс не будет завершен, процесс не будет помечен как завершено.

Пример кода:

procBox = []; // Global scope, stands for Process Box 

function loadPolygons() { 
    procBox["loadPolygons"] = "running"; 

    $.ajax({ 
     // ajax things here 

    }).done(function() { 
     procBox["loadPolygons"] = "done"; 
    }).fail(function() { 
     // failure stuff here 
    }); 
} 

function dependentFunction() { 
    if procBox["loadPolygons"] === "done") { 
     // The meat of the function (dependentFunction things here) 

    } else { 
     // Backup case that allows the browser to retry the request 
     /* -- 
     * If this fires, the server is still trying to process the 
     * ajax request. The user will be prompted to retry the request, 
     * and upon agreement, the function will be called again after 
     * 1 second passes. 
     */ 

     var msg = "Oops! It looks like we're still fetching your " 
       + "polygons from the server. Press OK to retry."; 

     if (confirm(msg)) { 
      setTimeout(dependentFunction, 1000); 
     } 
    } 
} 

Этот подход, кажется, хорошо работают в Firefox - alert() останавливает выполнение JavaScript и дает ему шанс для .done({}) обратного вызова происходит. Но по какой-то причине цикл while никогда не позволяет завершить обратный вызов .done({}) в Chrome!

Кто-нибудь знает, какой подход лучше для этого, чем использовать флаги или async: false?
Я ценю любые ответы и знания там!

+0

Не блокируйте javascript на неопределенный срок. Используйте тайм-аут или интервал. – tkausl

+0

Подробнее о 'Promise's. Тебе понадобится немного обернуть вокруг себя голову. – zero298

+0

Возможно, вы ищете '. Always (...)'. Это как 'finnaly'' try/catch', но для 'done/fail' jquery – notgiorgi

ответ

0

Есть множество способов сделать: как уже sugegsted вы можете использовать , так как вы используете JQuery, вы можете использовать пользовательские события https://learn.jquery.com/events/introduction-to-custom-events/:

$(document).on("myajax:done", function(){ dependentFunction();}) 
$.ajax({...}).done(function(){ 
    $(document).trigger("myajax:done") 
}); 

или даже глобального Аякс событие https://api.jquery.com/category/ajax/global-ajax-event-handlers/

но действительно подумайте, почему бы не сделать что-то вроде

procBox = {onLoadPolygons:dependentFunction}; // Global scope 

function loadPolygons() { 
    $.ajax({ 
     // ajax things here 

    }).done(function() { 
     procBox["onLoadPolygons"](); 
    }).fail(function() { 
     // failure stuff here 
    }); 
} 

function dependentFunction() { 
     alert("Please wait for the polygons to load"); 
    dependentFunctionThings(); 

} 
function dependentFunctionThings(){ 
    // Do dependent function things... 
} 

UPD: если вы ensist на вашу структуру, и по-прежнему хотите использовать блокирующие функцию использовать setInterval для выполнения работ по проверке

function dependentFunction() { 
    var h = setInterval(function() { 
     if (procBox["loadPolygons"] == "done") { 
      clearInterval(h); 
      // Do dependent function things... 
     } 
    }, 100); 
} 

Или завернуть в Promise (http://caniuse.com/#feat=promises)

function dependentFunction() { 
    (new Promise(function(resolve) { 
     var h = setInterval(function(){ 
     if (procBox["loadPolygons"] == "done") { 
      clearInterval(h);resolve(); 
     } 

     }, 100); 
    })).then(function(){ 
     // Do dependent function things... 
    }); 
} 

Но я все еще считаю, что что-то не так в вашей структуре

+0

Я думаю, что здесь что-то не хватает - код работает хорошо на firefox уже (просто не на Chrome). Мне нужно сделать паузу javascript на мгновение, чтобы проверить, завершился ли асинхронный алгоритм, прежде чем пользователь попытается снова редактировать данные. (Я не хочу, чтобы функция автоматически вызывалась после завершения $ .ajax - я просто хочу проверить, что она еще не обрабатывается, когда пользователь «dependFunction()» вызывается пользователем.) –

+0

@ Dylan, я не знаю, где и как называется ваша «dependFunction», но я удивлен, если он работает в Ff, как только вы запускаете бесконечный цикл, ваш процессор должен быть задушен, вы можете завернуть свой чек в setTimeout (() => {if (ajaxEnd == 1) doYourThings}, 100), но ваше «while» следует заменить на «if», сколько оповещений, которые вы получите после условия, будет истинным? – 2oppin

+0

Предупреждение() останавливает выполнение javascript в firefox - и обратные вызовы по-прежнему срабатывают за кулисами. В 9 раз из 10 завершается $ .ajax, прежде чем вы можете нажать [ok] на alert(), и он выходит из цикла при первой или второй попытке. Однако этот же подход не работает в хроме (приводит меня к мысли, что в этом подходе есть что-то принципиально неправильное). Я проверил его обертку в функции setTimeout(), и это похоже на то, что-бы это получилось, но я еще не реализовал ее. –

-1

Из документов:

.ajaxComplete() 

Всякий раз, когда запрос Ajax завершается, jQuery запускает событие ajaxComplete. Любые и все обработчики, зарегистрированные в методе .ajaxComplete(), выполняются в это время.

http://api.jquery.com/ajaxcomplete/

+0

Интересно - я думаю, что я следую. Могу ли я создать какую-то очередь вызовов функций, которые запускаются после завершения $ .ajax? Прямо сейчас, при попытке найти способ проверить, продолжает ли функция $ .ajax обрабатывать (с флагом procBox []), когда вызывается «dependFunction», когда пользователь нажимает кнопку. –

+0

На самом деле ajaxSuccess(), вероятно, будет лучше, поскольку он вызывается только тогда, когда запрос ajax выполняется с ответом HTTP 200. ajaxComplete() выполняется всегда, когда запрос ajax завершен. В любом случае, просто поместите свои функции ajax в функцию .ajaxComplete()/.ajaxSuccess() и поиграйте с ним. Документация JQuery и примеры довольно явные. – Kyobul

+0

Это не так, что я хочу, чтобы что-то произошло, как только запрос ajax завершился - мне просто нужно проверить, что он _has_ завершен. Он полностью работает в Firefox просто отлично! (Я обновил вышеприведенную тему, чтобы объяснить, что, по-видимому, неправильно с запуском этого через Chrome. Возможно, есть что-то, что мне не хватает с обещаниями) –

Смежные вопросы