2017-06-15 12 views
2

我已经构建了一个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

您有一个额外的大括号在第一个函数说它关闭了一个“if”。 – AtheistP3ace

+0

您应该等到当前正在运行的请求完成后再发送一个新的请求(并保留当前运行时可能发生的某些请求)。即使你使用'XMLHttpRequest2'的'abort'功能,这仍然会导致不必要的高服务器负载。 –

+0

可能重复[中止以前的AJAX调用时,一个新的?](https://stackoverflow.com/questions/9285271/abort-previous-ajax-call-when-a-new-one-made) –

回答

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

我修改该代码有点,只是将ajax请求存储到全局作用域的变量中,并在getData开始时在该变量上调用abort,但这种方法非常完美,谢谢。 – zachvac

+0

很高兴它的作品,我很高兴你学到了新的东西。 – vsync

+0

应该提到'abort'只会停止客户端的请求,但一旦它到达服务器,服务器可能仍然需要为请求执行整个处理,即使它被中止。所以它可能对服务器负载没有影响,并且如果这导致瓶颈,那么'abort'不会帮助,并且发出请求的数量应该被限制。 @zachvac –

-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 
-1

你可以简单地暂停它,例如500MIL秒,然后运行'最后'的变化,并做到这一点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吧:)

-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);