Reputation: 1325
I'm performing a live server side search while a user is typing in the browser. My seach functionality can't keep up with the typing pace, so requests pile up.
I want to be able to cancel queries that are replaced by new queries before the server is ready to respond.
This is what I want to achieve:
This way, only the most recent keystroke gets sent to the server, once the server ready. Of course, if there is no queue, a keystroke should just be sent straight to the server.
My current implementation is dead simple:
$.ajax({
type: "get",
dataType: "script",
data: {
search: "something"
},
url: "/api/search",
success: function(data, status, xhr) {},
error: function(xhr, textStatus, errorThrown) {}
});
Upvotes: 0
Views: 1183
Reputation: 7449
I think your approach is going to flood the server, because you're sending a request to the server on each keystroke. And even if you abort the request on the client side as @SravanS said, the server will still receive and start to process all of them. The HTTP request once sent is already on the net, you can't stop it, what you can do is no the client side abort it, which i assume notifies the server or just ignores the response it sends, but still you're flooding it.
Maybe implementing a delay to recognize when the user stopped typing would be the best approach. This is a generic delayed event handler factory, really easy to use, just pass your function to it and assign it a delay. If X miliseconds passed between keystrokes, a request will be sent, but if another keystroke happens before that delay, you're not even going to make a request.
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: This is how you can implement the queue, i haven't tested this code, use it as a starting point.
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));
Upvotes: 2
Reputation: 1131
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)
}
But in sendAjax do something like that:
.onSuccess = function () {flag = true;}
.onError = function () {flag = true;}
It is pretty primitive, but you can develop it, it is rather elastic than functional at this stage.
"But it works, and things that work - arent stupid" :)
Upvotes: 0
Reputation: 136
var req = $.ajax();
//kill the request
req.abort()
You can use $.ajax.abort method to kill the request. On each key press, kill the previous request, if there was one.
var prevReq = {};
elem.onkeyup = function(){
if(prevReq.abort)
prevReq.abort();
var prevReq = $.ajax(/*make the api call and clear prevReq object on response*/);
};
Upvotes: 0