当用户在浏览器中键入时,我正在执行实时服务器端搜索。我的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;}
它非常原始,但你可以开发它,在这个阶段它是有弹性的,而不是功能性的。
"但它是有效的,而且有效的东西并不愚蠢":)