Каков наилучший способ обрабатывать несколько транзакций по одной с помощью вызовов ajax? - PullRequest
0 голосов
/ 01 декабря 2009

Примечание: извините за количество псевдокода ниже, но я не знал, как еще показать, что я пытаюсь. На самом деле в моем решении намного больше кода, чем в моем решении, управляющем значком ajax и его состоянием, но я изобразил его, чтобы показать корень моей проблемы.

По сути, я пытаюсь создать цикл обработки на веб-странице и считаю, что это очень сложно. Что я хотел бы сделать, это отобразить список транзакций. В верхней части страницы я хочу предоставить пользователю кнопку «Обрабатывать все», которая будет обрабатывать каждую транзакцию по одной за раз. Во время обработки транзакции на сервере пользователь должен иметь возможность отменить цикл обработки. Это просто остановит отправку транзакции NEXT ; очень просто отменить. Тем не менее, из-за асинхронного характера вызовов ajax, я немного борюсь. (

У меня отлично работает в синхронном цикле. Тем не менее, пользователь не может нажать кнопку отмены, используя синхронный подход из-за его однопоточности. Вот что я придумал, пытаясь управлять этим в асинхронном цикле:

<a href="#" id="processAll">Process All</a>
<a href="#" id="cancelProcess">Cancel</a>
<table>
  <tr><td><a href="#" id="processLink1">Process</a></td></tr>
  <tr><td><a href="#" id="processLink2">Process</a></td></tr>
  <tr><td><a href="#" id="processLink3">Process</a></td></tr>
  <tr><td><a href="#" id="processLink4">Process</a></td></tr>
</table>

Ниже приведен код, который обрабатывает вышеуказанные ссылки:

var currentId = null;
var isWaiting = false; 
var userCancel = false;

$("#processAll").click(function(){

  $(this).hide();
  $("#cancelProcess").show();

  userCancel = false;

  // NOTE: this is where I think I need more logic...?

  processNextTransaction();

});

$("#cancelProcess").click(function(){

  $(this).hide();
  $("#processAll").show();

  userCancel = true;

});

$("a[id ^= processLink]").click(function(){

  var id = $(this).attr("id").replace(/^processLink(/d+)$/, "$1");
  doTransaction(id);

});

Ниже приведены вспомогательные методы, которые я использую в трех делегатах выше:

function processNextTransaction()
{

   var anchorId = $("a[id ^= processLink]:first").attr("id");
   var id = anchorId.replace(/^processLink(/d+)$/, "$1");

   function check() 
   {
     if (isWaiting)
       setTimeout(check, 500);
     else
     {
       if (!userCancel)           
         doTransaction(id);
     }
   }
   check();
}

function doTransaction(id)
{
   isWaiting = true;
   currentId = id;

   $.ajax({
       type: "POST",                
       url: "/Transactions/Process/" + id,
       data: {},
       success: successHandler,
       error: failHandler
   });

}

function successHander(result)
{
   // handle result...
   $("#processLink" + currentId).replaceWith(result);
   isWaiting = false;
}

function failHandler(result)
{
   alert("Error: " + result);
   $("#processLink" + currentId).replaceWith("Error!");
   isWaiting = false;
}

Обратите внимание, что я звоню processNextTransaction() только один раз, и это действительно моя главная проблема. Я подумал сделать это из successHandler и failHandler, но это противоречит цели флага setTimeout & isWaiting, а также вызывает другие проблемы, когда пользователь нажимает на одну ссылку «Процесс» для обработки одной транзакции. Это мой первый опыт со сценарием Ajax-циклов ... Пожалуйста, помогите! :)

Каков предлагаемый подход для управления списком процессов в асинхронной среде?

Ответы [ 2 ]

3 голосов
/ 01 декабря 2009

Это должно работать:

<a href="#" id="processAll">Process All</a>
<a href="#" id="cancelProcess">Cancel</a>
<table>
  <tr><td><a href="#" class="processLink" id="pl_1">Process</a></td></tr>
  <tr><td><a href="#" class="processLink" id="pl_2">Process</a></td></tr>
  <tr><td><a href="#" class="processLink" id="pl_3">Process</a></td></tr>
  <tr><td><a href="#" class="processLink" id="pl_4">Process</a></td></tr>
</table>

И магия jQuery:

var cancel = false;

$('#processAll').click(function() {    
    process($('.processLink:first'), true);
    cancel = false;
    return false;
});

$('.processLink').click(function() {
    process($(this), false);
    return false;
});

$('#cancelProcess').click(function() {
    cancel = true;
    return false;
});

function process(el, auto) {

    if(!cancel) {
        var id = parseInt(el.attr('id').replace('pl_', '')); // Get numeric ID

        $.ajax({
           type: "POST",                
           url: "process.php?id=" + id,
           success: function() {
               el.html('Processed');                     
               if(auto) { // If auto is true, process next ID                        
                   if($('#pl_'+(id + 1)).size() > 0) {                             
                       process($('#pl_'+(id + 1)), true);
                   }
               }
           }
       });
    }
}

Функция процесса использует обработчик успеха для обработки следующего элемента, если исходная функция процесса была вызвана с переменной automatic, установленной в значение true.

Отмена не отменит процесс, если он уже начался, очевидно.

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

Рабочий пример можно найти здесь: http://www.ulmanen.fi/stuff/process.php

0 голосов
/ 01 декабря 2009

Ваш код слишком длинный для чтения, но на основании вашего вступления я бы сделал что-то вроде этого:

Создать механизм организации очередей (в основном, массив). Когда пользователь хочет, чтобы транзакция была обработана, добавьте ее в очередь и вызовите функцию, которая выполняет что-то вроде doNextItemInQueue_unlessSomethingAlreadyRunning().

Эта функция берет первый элемент в очереди (в основном, URL), делает запрос ajax, ждет ответа и затем снова вызывает себя.

Если вы хотите разрешить прерывание очереди, разрешите установить флаг (например, abort_queue) и проверьте его перед запуском doNextItemInQueue_unlessSomethingAlreadyRunning().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...