What is the best way to periodically request URL and cancel requests when required data is present in the response in plain Javascript?
Say, I am requesting posts URI that returns JSON and want to cancel requests when numberOfPosts attribute in response is equal than some N.
Thanks!
Combine setInterval() with your web service call and cancel the interval once you got the expected response via clearInterval().
MDN about setInterval():
Repeatedly calls a function or executes a code snippet, with a fixed time delay between each call. Returns an intervalID.
This is demonstration of setInterval approach from accepted answer that worked for me (getJSONResponse contains all request handling logic):
var POLL_INTERVAL = 50;
var URI = 'posts';
var timerId = setInterval(function() {
var response = getJSONResponse(URI);
if (response.numberOfPosts === N) {
// Process response
...
clearInterval(timerId);
}
}, POLL_INTERVAL);
Related
I have a function that should only continue after an AJAX call has been completed, but I want to be able to skip that AJAX call if I already have the data from last session in my localstorage.
My current code:
$.when(getAddresses()).done(function (data) {
addresses = data.data;;
localStorage['addresses'] = JSON.stringify(addresses);
{{Rest of the code that should be executed after the AJAX call}}
}
Thanks in advance!
Do it the other way around.
Check for the data locally and don't even send the request if you already have it.
Wrap the data in a promise so it will always have the same API no matter where you fetch it from.
async function get_data() {
let addresses = localStorage.getItem('addresses');
if (addresses) {
return JSON.parse(addresses);
}
let ajaxData = await getAddresses();
addresses = ajaxData.data;
localStorage.setItem('addresses', JSON.stringify(addresses));
return addresses;
}
get_data().then(data => {
// Rest of the code that should be executed after the AJAX call
});
Another approach would be to forget about localStorage and just have the web service set suitable caching headers. Then you can make the HTTP request, but if the cache information shows that the browser cache contains up to date data it won't make the HTTP request at all.
You don't need to reinvent local caching of data. HTTP has it baked in.
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'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)
}
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
What is the best way to set timeout that will force my page not to set more than one ajax request per minute
Thanks in advance!
I'd use a simple variable holding the timerId returned from setTimeout. Something like this:
var timerId;
var doRequest = function(){
if(timerId) return;
timerId = setTimeout(doRequest, 60*1000);
// ajax code here
};
This will throttle the request to once per minute. If you need to stop the setTimeout call, then simply add another boolean based off the user event you are watching for.