Как предотвратить блокирование ответа 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!!!