Stop AJAX call from executing query - javascript

In my web application, on click on a specific button, AJAX call is triggered. On the server side, I want to execute a query to a DB.
Now, I am thinking about this, there are queries that are executing for some period, and maybe user isn't patient enough to wait for the results, and wants to stop the execution.
Is there a way to add one more button, that when clicked could stop previous AJAX call from executing and ALSO stop execution of a query? And is it a safe approach?
I am using angularjs, alongside with C# on server side.

related answers on your question
client side is streight forward
How to cancel/abort jQuery AJAX request?
but serverside is not as easy as client side, here related post to move forward
How do you cancel an AJAX long running MVC action client side (in javascript)?

The best way to go about "cancelling" your request on the client side is by taking advantage of the $q service, creating a deferred and then attaching it to your request using the "timeout" property for the $http({}) function call.
function sendSomeRequestToServer() {
var requestCanceler = $q.defer();
var request = $http({
method: "get",
url: "/your/url",
timeout: requestCanceler.promise
});
var promise = request.then(function(response) {
return response.data;
});
promise._requestCanceler = requestCanceler;
return promise;
}
function cancel(requestPromise) {
if (promise && promise._requestCanceler && promise._requestCanceler.resolve) {
promise._requestCanceler.resolve();
}
}
Most likely these functions would be wrapped in the same angular service. Credit to Ben Nadel and his blog for the tutorial and code.

Related

Calling a Callback after an event has been fired

I have recently been working on a project with both a client (in the browser) and node.js. I am using web sockets to communicate between the two. I have implemented an API on my server that communicates over the WebSockets and the server works just fine. In the browser, I am implementing the following class (in javascript) to interface with the API.
class ApiHandlerV1 {
constructor(apiUrl) {
//create the object
this.ws = null;
}
makeRequest(request,callback) {
//make a request
}
connect() {
//connect the websocket
this.ws = new WebSocket(this.url);
this.ws.onmessage = function () {
//call callback?
}
}
}
The issue that I am caught up on is that I want to be able to call makeRequest, provide a callback, and once the socket has gotten data back trigger the callback. I have thought about just re-defining .onmessage every time that I make a request but that just seems dirty to me and there is most likely a nice and easy solution to this.
Clarifications: Because of how I implemented my server I will only get a single message back from the server.
As Dominik pointed out in the comments I should also say that I am going to call .connect() before I make a request. I will be calling makeRequest multiple times after in other parts of my code.

node.js and hapi: fetching data from a database synchronously

Coming from a .net world where synchronicity is a given I can query my data from a back end source such as a database, lucene, or even another API, I'm having a trouble finding a good sample of this for node.js where async is the norm.
The issue I'm having is that a client is making an API call to my hapi server, and from there I need to take in the parameters and form an Elasticsearch query to call, using the request library, and then wait for the instance to return before populating my view and sending it back to the client, problem being is that the request library uses a callback once the data is returned, and the empty view has long been returned to the client by then.
Attempting to place the return within the call back doesn't work since the EOF for the javascript was already hit and null returned in it's place, what is the best way to retrieve data within a service call?
EX:
var request = require('request');
var options = {
url: 'localhost:9200',
path: {params},
body: {
{params}
}
}
request.get(options, function(error, response){
// do data manipulation and set view data
}
// generate the view and return the view to be sent back to client
Wrap request call in your hapi handler by nesting callbacks so that the async tasks execute in the correct logic order. Pseudo hapi handler code is as following
function (request, reply) {
Elasticsearch.query((err, results) => {
if (err) {
return reply('Error occurred getting info from Elasticsearch')
}
//data is available for view
});
}
As I said earlier in your last question, use hapi's pre handlers to help you do async tasks before replying to your client. See docs here for more info. Also use wreck instead of request it is more robust and simpler to use

How much of `$.post` is blocking?

I have a form collecting some information that I use $.post to handle an ajax request.
$.post(ajaxEndpoint, dataObject)
.done(function (response) {
if (response.status === 'success') {
// Send data to process asynchronously
otherApiCall(response.otherData);
// Redirect to the thank you page
window.location.replace(getThankYouUrl());
}
});
function otherApiCall (data) {
$.post(otherAjaxEndpoint, data);
}
The problem I have, from what I'm guessing, is that it redirects too quickly before the other POST can be made. But I do want it to POST asynchronously then redirect so the user isn't waiting for that second response. I don't care what the result of the second response is. I just want to finish the first response, send a second POST and the redirect immediately to cut down on the user looking at a spinner.
My second $.post seems like it doesn't get sent in time before the redirect happens because I never get the data from it. If I comment out the redirect, I do. I don't want to wait until the second done() but I can't figure how not to. What am I not understanding and/or doing wrong?
Additional Information/Update
I do have control over the server side handling. Is there something on that end that I could do to get a response quickly without waiting for the rest of the processing to finish?
You probably want to let the second post complete and then do the redirect.
A simple fix would be to return the $.post from second method and use done() of the second call to manage the redirect
$.post(ajaxEndpoint, dataObject)
.done(function (response) {
if (response.status === 'success') {
// Send data to process asynchronously
otherApiCall(response.otherData).done(function(){
// second post call now complete
// Redirect to the thank you page
window.location.replace(getThankYouUrl());
}).fail(function(){
// handle failed response
});
}
});
function otherApiCall (data) {
return $.post(otherAjaxEndpoint, data);
}
The best way to send data back to a server without having to wait for it to complete would be to use the navigator.sendBeacon API.
navigator.sendBeacon('/url/to/handler', yourData);
Quote from MDN:
Using the sendBeacon() method, the data will be transmitted asynchronously to the web server when the User Agent has had an opportunity to do so, without delaying the unload or affecting the performance of the next navigation.
Your data will have to be made into a ArrayBufferView, Blob, DOMString, or FormData, and I'm not sure if it is technically a POST request or not, but the request will persist after redirection.
It is currently supported in Firefox 31+, Chrome 39.0+, Opera 26+. For other browsers, you would have to do something else. You can feature-detect like so.
if (navigator.sendBeacon) {
// Use sendBeacon API.
}
else {
// Something else.
}
The redirect is probably cancelling the AJAX request that has been queued, but not yet sent. Try doing the redirect after a timeout, to give the second AJAX call a chance to be sent.
$.post(ajaxEndpoint, dataObject)
.done(function(response) {
if (response.status === 'success') {
// Send data to process asynchronously
otherApiCall(response.otherData);
// Redirect to the thank you page
setTimeout(function() {
window.location.replace(getThankYouUrl());
}, 10);
}
});
I'm not sure how reliable this is, though. Perhaps a better solution would be to perform the redirect when the second AJAX call goes to readystate == 3, which means the server is processing the request. There's no jQuery interface to this, so you'll probably have to do it using the low-level XMLHttpRequest interface.

If Javascript is not multithreaded, is there any reason to implement asynchronous Ajax Queuing?

I am having issues with my php server (my computer is the only connection). I initially thought part of the reason was because of too many ajax requests (I have a script that executes an ajax request per keystroke) so I implemented a design to control the flow of ajax requests into a queue. Below is my code:
//global vars:
activeAjaxThread = 0; //var describing ajax thread state
ajaxQue = []; //array of ajax request objects in queue to be fired after the completion of the previous request
function queRequest(ajaxObj) {
ajaxQue.push(ajaxObj);
if (activeAjaxThread == 0) {
fireOffAjaxQue();
} else {
return 'ajax thread is running';
}
}
function fireOffAjaxQue () {
activeAjaxThread = 1;
//getLastRequest();
if ((ajaxQue.length > 0) && activeAjaxThread == 1) {
$.ajax(ajaxQue[0]).always( function () {
ajaxQue.shift();
if (ajaxQue.length > 0) {
fireOffAjaxQue(); //fire off another ajax request since this one has been completed.
}
});
}
activeAjaxThread = 0; //thread has finished executing
}
Implementation:
//create ajax object
var ajaxObj = {
url: 'someplace.php',
data: dataVar,
success: function (data) {...}
};
//send ajax object to que
queRequest(ajaxObj);
Then I found out that Javascript is multi-threaded and read a few articles on Javascript's event handling, such as this on http://ejohn.org/blog/how-javascript-timers-work/ by John Resig (jQuery extra-ordinaire)
That being the case, wouldn't the functions I've presented here produce no results since Javascript is already queuing my requests? The weird thing is that it appears to change it drastically. My server crashes less, (not that that deems it a solution in any stretch of the imagination... argh), and after it crashes and restarts, the previous queued ajax requests get sent, when earlier they seemed to all be sent at once and disappear into thin air on server crash.
If Javascript, being single-threaded, queues asychronous events:
Is there any point to having an Ajax request manager, or a queue?
Why does my code produce any results at all?
Javascript is single threaded, but once the AJAX request is sent, it is out of javascript's hands, so to speak. That's the Asynchronous part of AJAX. The request is made and then the code moves on. Then when the response is received it is processed. Requests are not queued.

Implementing comet on the client side

I'm trying to implement comet in my application and, being inexperienced with JavaScript, I'm not sure how to do the client side.
When the server receives a request, it just keeps it open and writes data to it when necessary:
def render_GET(self, request):
print "connected"
request.write("Initiated\r\n")
reactor.callLater(random.randint(2, 10), self._delay, request)
return NOT_DONE_YET;
def _delay(self, request):
print "output"
self.count += 1
request.write("Hello... {0}\r\n".format(self.count))
reactor.callLater(random.randint(2, 10), self._delay, request)
I've been using jQuery on the client side so far, but I can't figure out how to make it work with the server. I've been looking at the jQuery.AJAX documentation and none of the callbacks say "Hey! I just received some data!", they only say "The request is finished."
I thought the dataFilter() function was what I wanted since it lets you handle the raw data before the request finishes, but it only lets you do it just before the request finishes, and not as you receive data.
So how can I receive data continuously through an open request? As you can see in the python example, each piece of data is delimited with \r\n so I want the JavaScript to behave like a line receiver. Is this possible with jQuery or do I have to play with XMLHttpRequest/ActiveXObject directly? Is there a (simple, lightweight) library available which implements a line receiver for me?
I'm hoping to hear about an existing library and how to implement this myself, since I've had bad bad luck with comet libraries so far, and at this point I'm hoping to just write the code I need and not bother with an entire library.
After looking at some other Comet/jQuery questions, I stumbled across this: http://code.google.com/p/jquerycomet/, which looks to be a jQuery plugin that does what you're after. If you're looking to see how it works, I'd just dig into the source.
The question where I found some great information is here.
A standard technique is to do a long polling request via AJAX (standard call with a really long timeout), then when receiving a response have your callback initiate another long poll when it is invoked. If the timeout expires, then you reissue the request using the error handling mechanism. Rather than having a single long request that periodically does something (like the "infinite iframe" technique), this uses a series of long requests to get data as the server has it available.
function longPoll( url, data, cb )
{
$.ajax({
url: url,
data: data,
timeout: Number.MAX_VALUE,
...other options...
success: function(result) {
// maybe update the data?
longPoll( url, data, cb );
cb.call(this,result);
},
error: function() {
longPoll( url, data, cb );
}
}
}
this code is the simpliest I have ever seen.
var previous_response_length = 0
, xhr = new XMLHttpRequest();
xhr.open("GET", "http://127.0.0.1:7379/SUBSCRIBE/hello", true);
xhr.onreadystatechange = checkData;
xhr.send(null);
function checkData() {
if(xhr.readyState == 3) {
response = xhr.responseText;
chunk = response.slice(previous_response_length);
previous_response_length = response.length;
console.log(chunk);
}
};

Categories