I have an application that gets an authentication token in every service call's response and it is supposed to send the previous token as a parameter for the next call otherwise user will be unauthorized. And once the token is mismatched, all the other calls fail.
To make sure that the tokens are not mismatched, i have added loaders on my screen and i display them as soon as an ajax call is initiated and keep the loading overlay on screen until the response is not received otherwise the user could click on any other link which would result in another ajax call.
But still, i think the loader mechanism is prone to loopholes. Is there any way to check if any ajax call is in progress, then queue the new one and the queued one shall wait for the initiated ones response because it would need the token returned from its response as its new request parameter.
I just worked on a project where I did this. Let's say you've got your AJAX function, foo.ajax( url, callback ).
You need a way to package all the details that would go out in an AJAX request. So you make a function foo.ajaxRequest(url) and a list of requests, foo.requestList = [] and use them like this:
foo.ajaxRequest = function( url ) {
foo.requestList.push(this);
var callback = function( data ) {
if ( foo.requestList.length ) {
foo.requestList.shift().run( data );
}
}
this.run = function( dataFromPreviousAjax ) {
foo.ajax( url + "?key=" + dataFromPreviousAjax, callback );
}
if ( !foo.requestList.length ) {
foo.ajax( url, callback );
}
}
and any time you want to make some requests, you write
new foo.ajaxRequest("http://stackoverflow.com/pingback.php");
new foo.ajaxRequest("http://stackoverflow.com/pingback.php");
and now suppose the first request returns a key of 12345, the second request will now run and call the url "http://stackoverflow.com/pingback.php?key=12345".
Obviously you'd want to do more stuff with the return value in the callback function inside foo.ajaxRequest, but this should get you started.
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.
If there is jquery ajax loading and I fire another ajax by quickly clicking the button, it kind of gets stuck. How can I handle multiple requests fired together?
How do I do following?
Discard/abort all previous requests and only process the latest one.
Do not allow new request until previous request completes (variation: can be same ajax request or any new ajax request from the page).
AJAX is Asynchronous. So you can fire them at the same time.
Or in the success callback (or .done() callback), you can call one request after another. So it will be easy to manage your issue (you click the button but get stucked), because you can control.
$.ajax({
url: "http://..."
})
.done(function( data ) {
// Other AJAX call
// or restore disabled elements
// while you were receiving the response.
});
If you want a work-around, just tell me.
you can use ajax "beforeSend" to lock the current request.So that user can send a new request only if the previous one is done. As for the process sequence, you can use a global value to store data and always assign it with the new response value.
function request(callback){
if(!$btn.hasClass('disabled')){
$.ajax({
type:'...',
url:'...',
beforeSend:function(){
$btn.addClass('disabled');//so that user cannot send a new request
},
success:function(data){
window.g_data = data;
callback && callback()//success callback
$btn.removeClass('disabled');
}
})
}
}
function callback(){
//process window.g_data
}
Have a look at this library:
Async is a utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript.
Async
Problem!
While trying to perform a set of AJAX request, most of the time at least one of the request is always getting a pending response, this is resulting in a loop of requests until it gets a succesful response. Please note that I using jQuery.when, this way I can ensure that both requests have been executed.
The mentioned behaviour is resulting on:
Multiple requests to the same source
jQuery.always is executes as many times as requests performed
The interface is crashing due to multiple updates on it's DOM.
Example
var request = [];
request.push(getProductPrice().done(
function(price) {
updateProductPrice(price);
}
);
request.push(getProductInfo().done(
function(information) {
updateProductInformation(information);
}
);
jQuery.when.apply(undefined, request).always(function() {
doSomeStuff1();
doSomeStuff2();
...
...
...
doSomeStuffN();
});
function updateProductPrice(obj) {
return jQuery.get(...);
}
function updateProductInformation(obj) {
return jQuery.get(...);
}
Questions?
Is there any reason on why I am getting a pending response?
Is this problem realted to jQuery.when trying to release the AJAX request in order to fire-up the callbacks?
Facts
If I do the request to the mentioned sources via synchronous, I will never get a pending response. I am just trying to avoid the use of async: false.
Update #1
By pending status I meant the response given by the web browser to my request, which is nothing but the ajax call waiting for it's response. The main problem resides on how those AJAX request are being treated, I am noticing that the functions updateProdcutPrice() and updateProductInformation() are being called N times until the response from the server is succesful, this is resulting that the functions declared on the .always()'s callback for the requestes performed on updateProdcutPrice() and updateProductInformation() are also being called that many times.
I am implementing a queue system of various information. When it reaches a certain number, I send an ajax request.... user inputs data, when it reaches certain point I send it. BUT, the user can still be entering data. I don't want to lose that.. so, I was thinking of I could use a $.Deferred/promise, while storing the data to a certain point.. firing ajax, and only allow a new request when the previous deferred is successful... also, if the data being entered then increased to the point I have to send it again, I que it..
I am having a hard time wrapping my brain around the methodology of how to implement.
===> capture data
=======> 'n' amount of data is entered
=============> move that data into the 'ready' bucket. (arbitrary, lets user entered 10 input fields and I store into an array. when array reaches 10.. boom send it ).
=============> fire ajax with the 10 items
In the meantime the user can still be entering data. I want to make sure I still capture it and keep que'ing and sending at 10.
I was thinking of a queuing system with a deferred. Not sure if I am over thinking this.
Since the jqXHR object returned by $.ajax() is a Promise, that can be used.
var data = {
// captured data goes here
};
function sendData( val ){
// jqXHR object (which contains a promise)
return $.ajax('/foo/', {
data: { value: val },
dataType: 'json',
success: function( resp ){
// do whatever needed
}
});
}
function when(){
$.when(sendData(data)).done(function (resp) {
when();
});
}
when(); // use this within the if switch
DEMO
Assuming your queue is the array dataQueue, then you can do something like this :
var dataQueue = [];//sacrificial queue of items to be sent in batches via AJAX request
var batchSize = 10;
var requesting = false;//flag used to suppress further requests while a request is still being serviced
//addToQueue: a function called whenever an item is to be added to he queue.
function addToQueue(item) {
dataQueue.push(item);
send();//(conditional on queue length and no request currently being serviced)
}
function send() {
if(dataQueue.length >= batchSize && !requesting) {//is the queue long enough for a batch to be sent, and is no ajax request being serviced
$.ajax({
url: '/path/to/server/side/script',
data: JSON.stringify(dataQueue.splice(0, batchSize)),//.splice removes items from the queue (fifo)
... //further ajax options
}).done(handleResponse).fail(handleFailure).always(resetSend);
requesting = true;
}
}
function handleResponse(data, textStatus, jqXHR) {
//handle the server's response data here
}
function handleFailure(jqXHR, textStatus, errorThrown) {
//handle failure here
}
function resetSend() {
requesting = false;//Lower the flag, to allow another batch to go whenever the queue is long enough.
send();//Call send again here in case the queue is already long enough for another batch.
}
DEMO
Notes:
There's no particular reason to return the jqXHR (or anything else) from send but by all means do so if your application would benefit.
resetSend needs not necessarily be called as the .always handler. Calling from the .done handler (and not the .error handler) would have the effect of "die on failure".
To minimise the number of members in your namespace (global or whatever), you might choose to encapsulate the whole thing in a contructor function or singleton namespace pattern , both of which are pretty trivial.
Encapsulating in a constructor, would allow you to have two or more queues with the desired behaviour, each with its own settings.
The demo has a few extra lines of code to make the process observable.
In the demo, you can set the batchsize to 15, add-add-add to get the queue length up to, say, 12, then reduce the batchsize to 5 and add another item. You should see two sequential requests, and 3 residual items in the queue.
I'm writing some JavaScript/AJAX code.
Is there anyway to ensure that the server receives the XML requests in the order that they are sent?
If not with plain Ajax, do I get this guarantee if I send everything over a single WebSocket?
Thanks!
If it is of utmost importance that they're received in the proper order, and attaching an iterating id to the form isn't enough:
msg_number = 1; sendAJAX(msg_number); msg_number++;
Then I'd suggest building your own queue-system, and send each subsequent file as the callback of the previous one.
Rather than each element having its own AJAX-access, create one centralized spot in your application to handle that.
Your different AJAX-enabled sections don't even need to know that it is a queue:
AJAX.send({ url : "......", method : "post", success : func(){}, syncronous : true });
On the other side of that, you could have something like:
AJAX.send = function (obj) {
if (obj.synchronous) {
addToSyncQueue(obj); checkQueue();
} else { fireRequest(); }
};
Inside of your sync queue, all you'd need to do is wrap a new function around the old callback:
callback = (function (old_cb) {
return function (response) {
checkQueue();
old_cb(response);
};
}(obj.success));
obj.success = callback;
AJAX.call(obj);
Inside of checkQueue, you'd just need to see if it was empty, and if it wasn't, use
nextObj = queue.shift(); (if you're .push()-ing objects onto the queue -- so first-in, first-out, like you wanted).
A couple of options come to mind:
Send them synchronously, by waiting for a successful response from the server after each XML request is received (i.e. make a queue).
If you know the number of requests you'll be sending beforehand, send the request number as a tag with each request, e.g. <requestNum>1</requestNum><numRequests>5</numRequests>. This doesn't guarantee the order that they're received in, but guarantees that they can be put back in order afterwards, and has the added benefit of being sure that you have all the data.
At my company we use this little ajaxQueue plugin, written by one of the core jQuery contributors:
http://gnarf.net/2011/06/21/jquery-ajaxqueue/