2016-05-10 4 views
1

Я создаю массив и нажимаю AJAX-запросы, используя jquery $.ajax с функцией $.each. Я хочу, чтобы после завершения массива страница обновлялась, но когда я пытаюсь сделать это, страница обновляется между ними. Когда я использую async:false для $.ajax запросов, он работает нормально, но это приводит к ухудшению производительности (время, необходимое для завершения аякс-запросов в 5 раз). Может кто-нибудь дать мне указатели о том, как это сделать, следуя код, который я поставил в:Обновить страницу после завершения функции .hach

$('#update1').click(function() 
{ 
    $.each(testarray,function(k,valu) 
    { 
     var count = testarray.length; 
     var checkloop = k+1; 
     var valkor = "/webresources/api/v3/sites/current/pages/" + valu.value; 
     var valkis = valu.checkbox; 

     var request = 
      $.ajax(
      { 
       url: valkor, 
       processData: false, 
       data: JSON.stringify({ "enabled" : valkis }), 

       type: "PUT",  
       contentType: "application/json", 
       mimeType: "application/json ", 
       headers: { "Authorization": $.cookie('access_token') } 
      }) 

     request.done(function(msg) 
     { 
      console.log("successfully updated"); 
     }) 

     request.fail(function(jqXHR) 
     { 
      console.log("Request failed."); 
      console.log("Error code: " + jqXHR.status); 
      console.log("Error text: " + jqXHR.statusText); 
      console.log("Response text: " + jqXHR.responseText); 
     }) 

     request.then(function() 
     { 
      location.reload(true); 
     }) 
    }) 
}) 

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

+0

Вы действительно не должны использовать 'асинхронные: false' при принятии AJAX звонков, как это может вызвать всевозможные неприятные побочные эффекты так как весь ваш код по существу будет «застрял», ожидая завершения каждого запроса (и он полностью победит цель A в AJAX). –

+0

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

ответ

1

Вы можете использовать jQuery .when, чтобы отложить действие до окончания все AJAX просит завершить.

Что-то вроде этого:

function updateHandler() 
{ 
    var promisesArray = []; 
    var successCounter = 0; 
    var promise; 

    $.each(testarray, function(k, valu) 
    { 
     var count = testarray.length; 
     var checkloop = k+1; 
     var valkor = "/webresources/api/v3/sites/current/pages/" + valu.value; 
     var valkis = valu.checkbox; 

     promise = 
      $.ajax(
      { 
       url: valkor, 
       processData: false, 
       data: JSON.stringify({ "enabled" : valkis }), 
       type: "PUT",  
       contentType: "application/json", 
       mimeType: "application/json ", 
       headers: { "Authorization": $.cookie('access_token') }, 
      }); 

     promise.done(function(msg) 
     { 
      console.log("successfully updated"); 
      successCounter++; 
     }); 

     promise.fail(function(jqXHR) { /* error out... */ }); 

     promisesArray.push(promise); 
    }); 

    $.when.apply($, promisesArray).done(function() 
    { 
     location.reload(true); 
     console.log("WAITED FOR " + successCounter + " OF " + testarray.length); 
    }); 
} 

$('#update1').click(updateHandler); 

Обратитесь к документации для $.when.

Поскольку jQuery 1,5, звонки, подобные $.ajax, возвращают обещание. Они полезны для разных вещей (см. this post для других полезных вещей о обещаниях), но в нашем случае мы хотели бы собрать обещания подать на звонок $.when, чтобы отложить выполнение фрагмента кода пока все запросы AJAX не возвратят ответ.

В цикле $.each мы определяем вызовы $.ajax. Как только каждый из них определяется - после каждого звонка до $.ajax - запрос отправляется по сети, и браузер будет ждать ответа. Кроме того, мы собираем связанный обещание для каждого отдельного вызова $.ajax в переменной. В приведенном выше коде мы выполняем две вещи с каждым из этих обещаний: 1) добавляем индивидуальные done и error функции для принятия мер - по индивидуальному запросу - после завершения каждого вызова; 2) мы сохраняем обещание в promisesArray, чтобы мы могли принять меры только после того, как все звонки завершены.

Важная вещь, чтобы отметить здесь, что эта строка: promise = $.ajax(... не сохраняет результат - то есть ответ - вызова AJAX, он сохраняет обещание, связанное с вызовом AJAX.

Наконец, мы передаем эти обещания $.when, который использует свою собственную функцию done, чтобы выполнить действие, которое мы хотим предпринять, только после того, как все вызовы AJAX вернулись.

Решение выше собирает множество обещаний, поскольку мое предположение из вашего вопроса и ваше использование testarray заключается в том, что мы не знаем заранее, сколько вызовов AJAX будет необходимо. Если вы сделали знать, сколько AJAX вызовов, которые вы будете использовать, мы можем удалить promisesArray из раствора, который может выглядеть примерно так и в случае 3 AJAX звонков:

$.when(
    $.ajax(/* args for 1st call */).done(/* 1st call success code */), 
    $.ajax(/* args for 2nd call */).done(/* 2nd call success code */), 
    $.ajax(/* args for 3rd call */).done(/* 3rd call success code */) 
    ).done(function() 
     { 
      location.reload(true); 
     }); 

Поскольку мы не знаем как необходимо много вызовов, напримериз-за пользовательского ввода, нам нужно собрать обещания, связанные с неизвестным номером звонков $.ajax.

Перед JQuery поддерживается отложенное выполнение - перед JQuery 1.5 - еще один способ справиться с проблемой принять меры только после того, как эти другие N (обычно AJAX) действий полных была держать большое переменное состояние: с N действиями для завершения вы создаете массив из N булевых элементов. Когда каждое действие завершено (вызов AJAX возвращен), обработчик done выполнил бы две вещи: 1) установить его флаг в true; 2) проверьте, установлены ли все, флаги установлены на true, а затем выполните действие, например, для повторной загрузки страницы. Это работало из-за однопоточного характера обработки очереди событий JavaScript.

Есть еще несколько вещей, чтобы отметить здесь:

  • вам нужны apply потому $.when ожидает deferreds как отдельные параметры.
  • Я добавил счетчик, который увеличивается на каждом звонке AJAX done, если вы закомментируете звонок location.reload, вы должны увидеть - при условии, что вызовы PUT успешны - значение счетчика соответствует размеру testarray.
  • вы должны учитывать разницу между использованием $.when().done против $.when().always(), чтобы определить, что лучше подходит для вашего собственного кода.
  • Я потянул установку цепей $.each и $.when в отдельную функцию. Это несущественно, и вы можете оставить их в click, как в вашем исходном коде, и он все равно будет работать.
  • Я проверял это, добавив кнопку с update1 как id и нажав на https://httpbin/put в качестве вашего valkor URL.

Как правило, не используйте async: false; - когда вы делаете это, всегда создавайте резервную копию и ищите другой способ. jQuery/JavaScript всегда предоставляет один.

+0

Итак, в основном мы создаем пустой массив и нажимаем на него значение ajax-вызова. Как только значения вставляются в массив (после завершения аякс-вызовов), мы обновляем страницу, правильно? –

+0

@GauravAggarwal это немного сложнее, чем это. Я поправлю ответ более подробно. – pb2q

+0

@GauravAggarwal Я обновил ответ и сменил код, чтобы надеяться сделать код и объяснение более ясными. Кроме того, в моем исходном коде использовались обратные вызовы 'success' и' error', которые устарели; также представляется, что в этом случае использование этих устаревших обратных вызовов _may_ приводит к тому, что вышеперечисленная структура с обещаниями/отложенными не работает – pb2q

0

Принимая «A» из AJAX

С async:false, как правило, плохая идея, так как это может вызвать всевозможные блокировки поведения, которые действительно могут связываться с вашим опытом и для некоторых запросов он даже устаревшее в целом:

по JQuery 1.8, использование асинхронного: ложного с jqXHR ($ .Deferred) является устаревшими; вы должны использовать полные/успешные/обратные вызовы.

Принимая преимущество Обещания

JQuery однако поддерживает использование в when() и then() обещании функции, что позволит Вам хранить все Ваши запросы, выполнять их асинхронными, а затем выполнить функцию, когда у них есть все были завершены.

Вам просто нужно будет хранить каждый из ваших запросов в массив:

// Store your requests 
var requestsToProcess = []; 

// Build each request 
$.each(testarray, function(k, valu){ 
     // Push this request onto your array 
     requestsToProcess.push(
      $.ajax({ 
       url: "/webresources/api/v3/sites/current/pages/" + valu.value, 
       processData: false, 
       data: JSON.stringify({ "enabled" : valu.checkbox }), 
       type: "PUT",  
       contentType: "application/json", 
       mimeType: "application/json ", 
       headers: { "Authorization": $.cookie('access_token') }, 
       done: function(msg){ 
         console.log("successfully updated"); 
       }, 
       fail: function(jqXHR){ 
         console.log("Request failed."); 
         console.log("Error code: " + jqXHR.status); 
         console.log("Error text: " + jqXHR.statusText); 
         console.log("Response text: " + jqXHR.responseText); 
       } 
      }) 
    ); 
}); 

// Now that all of your arrays have been added, process them 
$.when(requestsToProcess).then(function(){ 
     // Everything has been processed, refresh 
     location.reload(true); 
}); 
Смежные вопросы