我已经构建了一个javascript应用程序,其中包含一些图表,其中包含一些用户可以更改的下拉过滤器。下拉列表都有事件监听器,它们提交服务器请求以获取数据(通过jquery ajax调用),然后绘制数据图形。问题是如果用户使用键盘快速浏览下拉列表的许多不同元素。
服务器调用大约需要一秒钟,因此如果他们快速滚动说20,这可能会导致累积。创建了20个不同的服务器请求,然后甚至不能保证在服务器请求成功时执行的最后一段代码将是最新的过滤器。
所以我的问题是什么是更改过滤器以杀死所有其他异步进程的最佳方法?这是相关的代码:
$("#filter").change(function(d) {
getData();
} //end of if
});
function getData() {
...
$.ajax({
url: myUrl
type: "GET",
dataType: "json",
success: function(d) {
[do some stuff]
} //end of success function
}); //end of ajax
} //end of getData
答案 0 :(得分:1)
将您希望中止的所有Ajax调用保存到某个变量中,然后可以中止最后一次调用。
这是一种非常常见的练习,当某些ajax调用可能多次发生时,在它有机会完成之前。
function getData(){
$filter.data('REQ') && $filter.data('REQ').abort(); // abort the last request before creating a new one
return $.ajax({
url:myUrl
type:"GET",
dataType:"json",
success:function(d){
[do some stuff]
}
})
}
var $filter = $("#filter");
$filter.on('change', function(d) {
$filter.data('REQ', getData())
});
当然,这是一种非常简化的代码方式,您应该以更加结构化的方式重写它,但它可以让您了解如何缓存最后一个ajax请求然后您有权中止它在发送新电话之前。
顺便说一句,你的头衔与这个问题无关。您正在询问如何处理一系列ajax调用,但询问事件。这个问题与事件无关,所以你应该改变标题以适应问题。
关于@ t.niese在评论中所说的内容更新:
在客户端限制请求也是一个很好的做法,因为服务器无法真正知道客户端是否已中止请求,如果它是一个资源要求严格的请求,它应该被限制。 但是,如果可能的话,我建议在服务器端而不是在客户端限制请求,因为客户端限制可能被绕过并且不是100%可靠,并且它“花费”相同的数量是时候在服务器端做这件事。
Can a http server detect that a client has cancelled their request?
答案 1 :(得分:-1)
我会放弃所有尝试在当前请求运行时发起调用getData
的新请求,并且只在当前请求完成后立即发送最后getData
次尝试。这将确保服务器负载不会变得不必要地高,因为只会运行一个请求。
var currentRequest;
var resubmitRequest;
function getData() {
// only start a new request id no current request is running
if (!currentRequest) {
resubmitRequest = false;
currentRequest = Promise.resolve($.ajax({
url: myUrl
type: "GET",
dataType: "json"
})); //end of ajax
currentRequest
.then((d) => {
[do some stuff]
})
.finally(() => {
// if the current request finished and another attempt to request data
// happened while this request was running then call getData again
if (resubmitRequest) {
getData()
}
})
} else {
// store the information that the data has to be requested
// another time after the currently running request finished
resubmitRequest = true;
}
return currentRequest;
} //end of getData
答案 2 :(得分:-1)
你可以简单地暂停它,例如500mil秒然后运行'last'更改并执行ajax调用..
$("#filter").change(function(d) {
if( $.active > 0 ) return false;
// do not run new ajax if last one is not finished
clearTimeout( window.timer );
// if new 'change' evt is raised in less then 500 mils
// then clear it and run 'last' one
window.timer = setTimeout( function(){
getData();
}, 500 );
});
如果用户在执行ajax时更改了它,return false
它:)
答案 3 :(得分:-1)
您可以毫不费力地为这些案例编写自己的handler
代码:
function handler(ms, fn) {
var eventId;
return function () {
// if there is an event programmed, kill it
clearTimeout(eventId);
// and program the new one (replace the event)
eventId = setTimeout(fn);
// if passed the time no event was programmed, setTimeout is going to execute the function
}
}
// execute getData if no event is fired in a 1000ms interval (the user stopped typing)
// getData is the same that you have
var fn = handler(1000, getData);
$("#filter").change(fn);