如何在服务器仍在处理以前的请求时对ajax请求进行排队

How to queue ajax request while the server is still processing previous request?

本文关键字:请求 ajax 排队 服务器 处理      更新时间:2023-09-26

当用户在浏览器中键入时,我正在执行实时服务器端搜索。我的seach功能跟不上打字的速度,所以请求越来越多。

我希望能够在服务器准备好响应之前取消由新查询替换的查询。

这就是我想要实现的:

  • 第一次击键应该发送到服务器
  • 下一个按键笔划应该由客户端脚本排队,直到服务器响应第一个查询
  • 在此期间,如果发生另一次击键,则应替换当前排队的击键

这样,一旦服务器准备就绪,只有最近的击键才会被发送到服务器。当然,如果没有队列,击键应该直接发送到服务器。

我目前的实现非常简单:

$.ajax({
  type: "get",
  dataType: "script",
  data: {
    search: "something"
  },
  url: "/api/search",
  success: function(data, status, xhr) {},
  error: function(xhr, textStatus, errorThrown) {}
});

我认为你的方法会淹没服务器,因为你在每次击键时都会向服务器发送一个请求。即使你像@SravanS所说的那样在客户端中止请求,服务器仍然会接收并开始处理所有请求。HTTP请求一旦发送就已经在网上了,你无法停止它,你所能做的就是客户端不中止它,我认为这会通知服务器或忽略它发送的响应,但你仍然在淹没它

也许实现延迟来识别用户何时停止键入是最好的方法。这是一个通用的延迟事件处理程序工厂,非常容易使用,只需将函数传递给它并为其分配一个延迟即可。如果两次击键之间相隔X毫秒,则会发送一个请求,但如果在延迟之前又发生了一次击键,则您甚至不会发出请求。

function delayedEvent(eventHandler, delay) {
    var lastTimeout = null;
    return function () {
        var that = this,
            args= Array.prototype.slice.call(arguments).sort();
        if (lastTimeout !== null)
            window.clearTimeout(lastTimeout);
        lastTimeout = window.setTimeout(function () {
            eventHandler.apply(that, args);
        }, delay);
    };
}
$('... selector ...').on('event', delayedEvent(function () { ... your code ... }, 500));

EDIT:这就是实现队列的方法,我还没有测试过这段代码,将其作为起点。

function eventQueue(requestMaker) {
    // Here we store the last event queued, it'll wait until all the already running events are done.
    var lastQueued = null,
        runningQueue = [];
    // Push a new event into the running queue
    function pushRunning(toPush) {
        runningQueue.push(toPush.done(
            // It is necesary to use an IIFE to get the index by value and not by reference
            (function (index) {
                return function() {
                    // Remove this event from the runningqueue
                    runningQueue.splice(index, 1);
                    // If the queue has been completed, start running the last event sent
                    if (lastQueued !== null && runningQueue.length === 0) {
                        pushRunning(lastQueued());
                    }
                }
            }(runningQueue.lenght));
        ));
    }
    return function () {
        var that = this,
            args = Array.prototype.slice.call(arguments).sort();
        // Some events are already running, just override the lastQueued
        if (runningQueue.length > 0) {
            lastQueued = requestMaker.bind(that, args);
        } else {
        // Nothing queued run this event straight away, and queue it as running
            pushRunning(requestMaker.apply(that, args));
        }
    };
}
$('... selector ...').on('event', eventQueue(function () { 
    // It's extremely important that you return the jquery $.ajax Promise
    return $.ajax(...);
}, 500));
var req = $.ajax();
//kill the request
req.abort()

您可以使用$.ajax.abort方法终止请求。在每次按键时,如果有前一个请求,则终止该请求。

var prevReq = {};
elem.onkeyup = function(){
    if(prevReq.abort)
        prevReq.abort();    
    var prevReq = $.ajax(/*make the api call and clear prevReq object on response*/);    
};
var arr = [], // bufor
    flag = true;
window.onkeydown = function (e) {
  arr.push(e);
  sync();
}
function sync() {
if(flag){
  flag = false;
  sendAjax(arr.shift());
  }
setTimeout(function () {
  sync();
}, 40)
}

但是在sendAjax中做一些类似的事情:

.onSuccess = function () {flag = true;}
.onError = function () {flag = true;}

它非常原始,但你可以开发它,在这个阶段它是有弹性的,而不是功能性的。

"但它是有效的,而且有效的东西并不愚蠢":)