Как предотвратить блокирование ответа POST-запроса последовательными GET-запросами?

У меня есть таблица, которая загружается пустой (без строк), а затем я запускаю вызов Ajax - внутри цикла django for-loop - для заполнения таблицы данными из функции python, которая каждый раз возвращает одну строку/элемент. Я делаю это для того, чтобы пользователи могли взаимодействовать с таблицей, пока данные загружаются на заднем плане (особенно полезно, поскольку таблица отображает много строк).

У меня также есть функция jquery, которая при нажатии правой кнопкой мыши на строке создает контекстное меню для этой конкретной строки, заполненное опциями динамически через AJAX. Проблема в том, что контекстное меню не всегда заполняется оперативно.

Как это работает: я щелкаю правой кнопкой мыши на строке и "захватываю" определенные параметры объекта в этой строке. Затем эти параметры передаются в функцию getTablePerms(), которая выполняет AJAX POST запрос к Python функции, которая - на основе этих параметров - возвращает разрешения элемента в строке и изменяет html div контекстного меню, по сути показывая опции контекстного меню.

Проблема в том, что пока строки добавляются в таблицу, щелчок правой кнопкой мыши на строке должен немедленно вызвать контекстное меню, но этого не происходит. Создается впечатление, что он ждет (что, скорее всего, так и есть) завершения большинства GET-запросов. Я применил два setTimeouts, чтобы заставить AJAX GET-запрос ждать несколько секунд, но хотя это работает при небольшом количестве строк (70 строк), при большем количестве (500+ строк) контекстное меню появляется не сразу, а после получения 200-ответов. POST-запрос отправляется вовремя, но его ответ задерживается.

Поэтому я решил, что последовательные GET-запросы блокируют своевременное выполнение POST-запроса, потому что когда у меня небольшое количество строк, контекстное меню появляется быстро.

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

Мой views.py

def myprotocol_item(request,pk):

    data = dict()
    protocoltype = request.GET.get('protocoltype')
    mytype = request.GET.get('type')
    queryset = Myprotocol.objects.filter(Q(pk=pk) & Q(del_f=0))
    context = { 'myprot':queryset[0]}  
    template = 'protocol/Myprotocol/list_table_body.html'
    data['html_form'] = render_to_string(template,context,request=request,)
    data['pk'] = pk
    return JsonResponse(data)

Мой вызов ajax:

{% if data %}
  {% for dataitem in data %}
  setTimeout(function(){
    $.ajax({
        headers: {'X-CSRFToken':getCookie('csrftoken')},
        url: "{% url 'protocol:myprotocol-item' dataitem.protocol_ptr.id %}",
        type: 'get',
        dataType: 'json',
        success: function(data) {
          var tablerows = $('#myTable1 #tbody tr').length;
         
          if (tablerows === 0){
            $("#myTable1 #tbody").append(data.html_form);  
          }
          else if (tablerows > 0){
           
            $("#myTable1 #tbody tr").last().after(data.html_form);

          }
          // let the plugin know that we made a update
          // the resort flag set to anything BUT false (no quotes) will trigger an automatic
          // table resort using the current sort          
          var resort = true;
          $("table").trigger("update", [resort]); 
          
   
        }, // end of success
        error : function(xhr,errmsg,err) {
          console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
        } // end of error   

    }); //end of ajax
  }
  ,3000);//end of SetTimeout
  {% endfor %}
{% endif %}

Мой rightclick.js

  $('body').contextmenu(function() {
    return false;
  });
  //==============contextMenu====================== //
  var $contextMenu = $("#contextMenu");
  var $id_page_content = $("#id_page_content");
  var $myTable1 = $("#myTable1");
  $('body').on("contextmenu", "#myTable1 tbody tr,#myTable2 tr",function(e) {

    var myid = $(this).attr('id').split('_')[1].replace('.', '');
    var mytype = $(this).attr('id').split('_')[2];
    var f = $(this).attr('id').split('_')[3];
    var mycontainerid = $(this).attr('id').split('_')[4];

    var obj_table = $(this).attr('data-obj-table').split('_')[1];
    var routeid = $(this).attr('data-obj-table').split('_')[2];
    

    console.log('myid '+ myid);
    console.log('folder ' + f);
    console.log('mytype ' + mytype);
    console.log('obj table ' + obj_table);
    console.log('obj route ' + routeid);
    console.log('mycontainerid ' + mycontainerid);

    getTablePerms(myid,mytype,obj_table,f,routeid,mycontainerid);
    
    if ($(window).scrollTop() < $(document).height() && e.pageY > $myTable1.height()-80 && e.pageY >= document.querySelector('[id^="myTable"]').offsetTop+200 && e.pageY >= $(window).height()-300){
    
       $contextMenu.css({
         display: "block",
         left: e.pageX,
         top: e.pageY-248,
    
       });
     }
     else {
      $contextMenu.css({
        display: "block",
        left: e.pageX,
        top: e.pageY,

      });
    }
    
  });
  $('#contextMenu').click( function(event){
    event.stopPropagation();
    $('#contextMenu').hide();
  });
  $('body').click( function(){
    
    $('#contextMenu').hide();
  });
  //==============End contextMenu====================== //

function getTablePerms(myid,mytype,obj_table,f,routeid,mycontainerid){
        $.ajax({
              type:"POST",
              dataType: "json",
              url: "/common/get/object/perms/",
              data:{'csrftoken':getCookie('csrftoken'),'obj':myid,'mytype':mytype,'obj_table':obj_table,'f':f,'routeid':routeid,'mycontainerid':mycontainerid},
              success: function(result)
              {
//========== JQUERY CODE TO MODIFY CONTEXT MENU ============//
              }// end of success
        });// end of ajax
}// end of function

Есть мысли?

Ответ пришел после небольшого поиска в виде AjaxQueue.

Проблема заключалась в том, что в то время как данные вызываются одним Ajax-запросом, он не позволяет выполнять другие вызовы, включая Ajax POST, который строит контекстное меню в зависимости от разрешений каждого элемента.

Вместо этого я сделал Ajax-запрос для передачи данных каждой строки таблицы в AjaxQueue, добавив ajaxQueue.js в заголовок шаблона списка и изменив ajax-запрос следующим образом:

{% if data %}
  {% for dataitem in data %}
    var jqXHR = $.ajaxQueue({
        headers: {'X-CSRFToken':getCookie('csrftoken')},
        url: "{% url 'protocol:myprotocol-item' dataitem.protocol_ptr.id %}",
        type: 'get',
        dataType: 'json',
        success: function(data) {
          var tablerows = $('#myTable1 #tbody tr').length;
         
          if (tablerows === 0){
            $("#myTable1 #tbody").append(data.html_form);  
          }
          else if (tablerows > 0){
           
            $("#myTable1 #tbody tr").last().after(data.html_form);

          }
        
          var resort = true;
          $("table").trigger("update", [resort]); 
          return false;          
   
        }, // end of success
        error : function(xhr,errmsg,err) {
          console.log(xhr.status + ": " + xhr.responseText);
        } // end of error   

    }); //end of ajax
  }

  {% endfor %}
{% endif %}

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

Большое спасибо @gnarf и их скрипту ajaxQueue!!!

Вернуться на верх