I'm sending an ajax request to the server on user's input to an <input> element, like this:
$('#my-input').bind("input", function(event){
// here's the ajax request
});
What bothers me is that it send unnecessarily many requests on every user's keyup, meaning that if the user types very fast, there are many unnecessary requests. So I get the idea that there should be a certain delay/timeout, which waits a certain time (50 miliseconds?) for the user to stop typing before sending the ajax request. That would be one problem solved.
But what about cases when the first ajax request haven't been completed before sending another request? (Typing 60 ms / char while ajax request taking 300 ms).
What is the best way to solve this problem (both idea- and code-based)?
You can use throttle function in underscore library. As its documentation says:
Creates and returns a new, throttled version of the passed function, that, when invoked repeatedly, will only actually call the original function at most once per every wait milliseconds. Useful for rate-limiting events that occur faster than you can keep up with.
Even if you don't want to introduce a new library, you can still get idea about how this function works from its source code. In fact, a simple version of throttle function could be:
function throttle(func, delay) {
var timeout = null;
return function() {
var that = this, args = arguments;
clearTimeout(timer);
timeout = setTimeout(function() {
func.apply(that, args);
}, delay);
};
}
This jQuery throttle-debounce plugin is also helpful. Especially, the debounce function seems more suitable to your needs than throttle function according to its author:
Debouncing can be especially useful for rate limiting execution of handlers on events that will trigger AJAX requests
You could just use the setTimeout function. Every so often, see if the text hasn't changed, and if it hasn't, then process accordingly.
setTimeout(function() {
// Do something after 1 second
}, 1000);
You can set async: false in your ajax request so it will process second ajax call only after completion of first ajax request.
I'd go with #HuiZeng's answer, but just in case you want a slightly modified version.
Steps
Listen to keydown using a setTimeout that you can clear.
When it fires, check if you have a previous request in queue, if so abort it and fire a new one
Example:
var inputTimer = 0, req;
function onInput(e){
clearTimeout(inputTImer);
inputTimer = setTimeout( function(){
// You have access to e here
// Cancel any previous requests
req && req.abort();
req = $.ajax({/*...Do your magic here :)*/})
}, 100)
}
Related
Working on a platform, to enable auto-ticketing functionality. For which a REST API request is used for ticket creation. Unfortunately, there are 2 requests popping simultaneously, which results in creating duplicated tickets.
How to handle such case and send only one of these requests?
Tried adding the 2nd request in the response callback of the first, though this does not seem to work.
if (flag == 1){
logger.debug("Node-down alarm-Request raised - +sitn_id);
clearTimeout(mouseoverTimer);
mouseoverTimer = setTimeout(function(){
logger.debug("Inside Call back function - ");
//function call for ticket creation
incidentRequest(sitn_id,confUtil.config.mule_url);
}, 10);
You really should show more of the code that makes the request, though it seems as if you are doing some ajax inside your 'incidentRequest', so I will presume that (if that isn't what you are doing, then please, show your code....) - and since you tags say javascript and jquery - well, here goes...
To stop the 'double send' in an AJAX call, it is simple:
function incidentRequest(sitn_id,confUtil.config.mule_url){
// stop the double by clearing the cache
$.ajaxSetup({cache: false});
// continue on with the AJAX call
// presuming the url you want is confUtil.config.mule_url
// and the data you want to send is sitn_id
$.post(confUtil.config.mule_url, 'sitn_id=' + sitn_id, function (data) {
// do cool stuff
});
}
Hopefully that will help you get moving. If not, then we will need more code of what is going on around all this.
I need a way of measuring the response time of a javascript function that creates an http request, that includes the response time of that http request. I do not have access to modify that funciton however.
Here's what I'm trying to do:
var startTime = performance.now(); //log start timestamp
foo.bar(); //The Function that generates an HTTP request
var endTime = performance.now(); //log end timestamp
var diffTime = endTime - startTime;
but that only captures the time it takes for the function to generate the request. Is there a way to capture the response time of the request that gets genearated in javascript?
You have to check the timestamp inside of the request callback.
EDIT:
If you want do measure this completely independently from the application (so just by adding another js file), I guess you can decorate XMLHttpRequest.
window.XMLHttpRequest = function () {...}
Your wrapper will need to have the same API, so that the app still works, and can also measure performance internally.
I would usually just hit F12 to bring up dev tools on any browser, go to the network tab, and look at the ajax call that is being made, that will tell you exactly how long the request and repose took with very fine grained details.
However, if you are looking to factor in the java-script that makes the ajax call then start your timer right before the call and stop it on the complete event of the ajax call (will require editing the function). that is the only way to catch it if it is asynchronous. And just guessing here based on your description that it is actually an async call, and that explains the behavior of the function just making the ajax call then returning - and not caring about the status or the response...
If you happen to be using jQuery in your inaccessible function, you can give this a shot:
$.when(foo.bar()).done(function()
{
console.log("Fired after ajax request is done!");
});
Take a look also at:
var obj = {
promise: function() {
// do something
}
};
$.when( obj ).done( fn );
or
var obj = {
promise: foo.bar()
};
$.when( obj ).done( callback );
or check out this great article http://www.erichynds.com/blog/using-deferreds-in-jquery
well, if you don't have an acces to the function or you can't edit the ajax call, you can create a listener. the strategy:
declare a flag befor the http request call
start the call
start a listener that loop every X mili-seconds and check for a finish status (outside the ajax function and after it is called)
you should ask yourself: which kind of variables are changed when this call is over? event a visual change on the ui can be used as a flag
and if you wonder how to create your listener.. it looks something like this:
function listener()
{
// do some checks here
if (done)
{
var endTime = performance.now(); //log end timestamp
var diffTime = endTime - startTime;
}
else
{
setTimeout(listener(), 100);
}
}
listener(); // activate the listener
I am triggering a change event in my casperJS script which triggers an AJAX request like such:
casper.evaluate(function(i) {
$("form:eq(2) select option:eq(" + i + ")").attr("selected", "selected").change();
},i);
How can I make casperJS wait until the underlying AJAX request has been finished? Already tried to look at the docs but I am more or less stuck. Can anyone guide me into the right direction?
You can always do this in a static way using casper.wait.
casper.thenEvaluate(function(i) {
// change()
},i).wait(5000).then(function(){
// further processing
});
And hope that the request is done in 5 seconds, but maybe you lose some time waiting when the request is done much sooner than 5 seconds. The problem is that as soon as the request is finished doesn't mean that the page is ready/changed.
Another possibility would be to wait for the request to finish, but for this to work you will need to register for the success event of the request somehow. Most of the time you don't have access to this from the global scope. If you do then you can use
casper.thenEvaluate(function(i) {
window._someUniqueVariable = false;
registerSuccessEvent(function(data){
window._someUniqueVariable = true;
});
},i).waitFor(function check(){
return this.evaluate(function(){
window._someUniqueVariable = true;
});
}, function(){
// further processing
});
A more Casper-way of doing that would be to use casper.waitForResource, but then you would need to know the url beforehand or at least able to deduce it from the page.
In the general case, when the request comes back it does something to your page. So you should be able to waitForSelector with a new element or waitForSelectorTextChange or waitUntilVisible etc.
you probably missed waitForResource
from the docs: http://casperjs.readthedocs.org/en/latest/modules/casper.html#waitforresource
casper.waitForResource("you url here", function()
{
// place your code here
});
I have about 100 ajax requests that I fire at the same time, I thought browsers only allowed a few requests simultaneously, so the rest would be added to a queue.
The problem however is that jquery/javascript seems to use the timeout value from the time the requests were created via jquery, not from the time the requests were actually executed by the browser. So I get a bunch of timeouts. Is it possible to have the timeout start counting from the time the request is actually going to the URI location, instead of the time it is added by jquery?
You may use the timeout settings for ajax request. You may find the jQuery documentation for the same at : http://api.jquery.com/jQuery.ajax/
However the timeout period starts at the point the $.ajax call is made; if several other requests are in progress and the browser has no connections available, it is possible for a request to time out before it can be sent. Therefore you should set some very large value for the timeout if you wish to follow this approach.
A better approach would be to have a local proxy which entertains all the AJAX calls and fires them in a group of 5-10 and then when all these have finished successfully then it fires the next 5-10 requests.
Here is a kind of queue system. Starts by calling the ajax function N times, and then after each success, calls ajax function again. There is also a check in the success callback to see if all the assets have been loaded...
demo fiddle
$(document).ready(function(e) {
$("form[ajax=true]").submit(function(e) {
e.preventDefault();
var form_url = $(this).attr("action");
var form_method = $(this).attr("method").toUpperCase();
$("#loadingimg").show();
var started = 1, done = 0;
function ajax(){
$.ajax({
url: form_url,
type: form_method,
data: "html=started "+(started++),
cache: false,
success: function(returnhtml){
done++;
$("#result").html(returnhtml);
$("#loadingimg").hide();
if(started <= 100){
ajax();
} else if (done == 100) {
alert("all done!");
}
}
});
}
// how many concurrent calls?
for(i=0;i<10;i++){
ajax();
}
});
});
We've all seen some examples in AJAX tutorials where some data is sent. They all (more or less) look like:
var http = createRequestObject(); // shared between printResult() and doAjax()
function createRequestObject() { /* if FF/Safari/Chrome/IE ... */ ... }
function printResult()
{
if (http.readyState == 4) { ... }
}
function doAjax() {
var request = 'SomeURL';
http.open('post', request);
http.onreadystatechange = printResult;
data = ...; // fill in the data
http.send(data);
}
// trigger doAjax() from HTML code, by pressing some button
Here is the scenario I don't understand completely: what if the button is being pressed several times very fast? Should doAjax() somehow re-initialize the http object? And if if the object is re-initialized, what happens with the requests that are being already on air?
PS: to moderator: this question is probably more community-wiki related. As stated here (https://meta.stackexchange.com/questions/67581/community-wiki-checkbox-missing-in-action) - if I've got it right - please mark this question appropriately.
Since AJAX has asynchronus nature, with each button click you would raise async event that would GET/POST some data FROM/TO server. You provide one callback, so it would be triggered as many times as server finishes processing data.
It is normal behaviour by default, you should not reinitialize of http object. If you want to present multiple send operation you have to do that manually (e.g. disabling button as first call being made).
I also suggest to use jQuery $.ajax because it incapsulate many of these details.
Sure that numerous libraries exist nowadays that perform a decent job and should be used in production environment. However, my question was about the under-the-hood details. So here I've found the lamda-calculus-like way to have dedicated request objects per request. Those object will obviously be passed to the callback function which is called when response arrives etc:
function printResult(http) {
if (http.readyState == 4) { ... }
...
}
function doAjax() {
var http = createRequestObject();
var request = 'SomeURL';
http.open('get', request);
http.onreadystatechange = function() { printResult(http); };
http.send(null);
return false;
}
Successfully tested under Chrome and IE9.
I've used a per-page request queue to deal with this scenario (to suppress duplicate requests and to ensure the sequential order of requests), but there may be a more standardized solution.
Since this is not provided by default, you would need to implement it in JavaScript within your page (or a linked script). Instead of starting an Ajax request, clicking a button would add a request to a queue. If the queue is empty, execute the Ajax request, with a callback that removes the queued entry and executes the next (if any).
See also: How to implement an ajax request queue using jQuery