Close specific XMLHttpRequest - javascript

How to "rebuild" function to close specific XMLHttpRequest? I have defined variable outside function to call xhr.abort(); everywhere I need. Now is possible, with this solution, close last running XMLHttpRequest if running more than one at same time - processes before last running are without control after replace xhr by re-calling _ajax()
var xhr;
function _ajax(data, callback) {
xhr = new XMLHttpRequest();
xhr.open('POST', window.location.pathname, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
callback(this);
}
};
xhr.send(data);
}
/* close fnc */
xhr.abort();

You could use xhr as an array and store there all the requests; then you can call abort on any one of them. Like:
var xhr=[];
function _ajax(data, callback) {
xhr.push(new XMLHpptRequest);
//etc
}
xhr[0].abort();
xhr.shift(); //get rid of the aborted request

Related

How to make callback run asynchronously?

I have a JavaScript function called getAandB which takes a callback. getAandB firstly gets value 'a' using ajax. It then invokes the callback with value 'a' as an argument. The callback gets value 'b' and console.logs both 'a' and 'b' to the console. so I get {"key":"a"} {"key":"b"} in the console.
I thought that the two ajax calls would happen simultaneously / asynchronously. However, they seem to run one after the other ie. synchronously.
The JavaScript code and the PHP code for the ajax requests is shown below:
index.html:
<script>
function getAandB(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
callback(xhr.responseText)
}
}
xhr.send();
}
function callback(resultA){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
const resultB = xhr.responseText;
console.log(resultA, resultB);
}
}
xhr.send();
}
getAandB(callback);
</script>
ajax-a.php:
<?php
sleep(5);
$response = [
"key" => "a",
];
echo json_encode($response);
The code for ajax-b.php is the same as for ajax-a.php except the value of $response.key is b not a.
I thought that the above code would result in ajax calls being made simultaneously to get 'a' and 'b'. However if the PHP code sleeps for 5 seconds for both ajax-a.php and ajax-b.php, then it takes 10 seconds for the console.log to appear. If only one of the ajax-?.php scripts sleeps for 5 seconds then it takes 5 seconds for the console.log to appear.
How can I use callbacks to allow me to combine the results of ajax calls, as I have done here, but to make the individual calls happen simultaneously / asynchronously? Alternatively, is not possible to implement this with callbacks?
If you want the request to ajax-b to me made at approximately the same time as the request for ajax-a then you need to make the respective calls to xhr.send() at approximately the same time.
At the moment, the call to ajax-b's send() takes place as part of callback() which you only call after you have received the response to the request for ajax-a.
You then need to add additional logic to determine when you have received both responses so you log both bits of data at the same time (assuming you still want to do that).
A rough and ready way to do that, keeping to your current approach, would look something like this:
function getA(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
callback(xhr.responseText)
}
}
xhr.send();
}
function getB(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
const resultB = xhr.responseText;
callback(xhr.responseText)
}
}
xhr.send();
}
function getAandB() {
const data = [];
function callback(responseData) {
data.push(responseData);
if (data.length === 2) {
console.log(...data);
}
}
getA(callback);
getB(callback);
}
getAandB();
We have better tools for that these days though, thanks to promises and modern APIs (like fetch) which support them natively.
async function getAandB() {
const dataPromises = [
fetch("./ajax-a.php").then(r => r.text()),
fetch("./ajax-b.php").then(r => r.text())
];
const data = await Promise.all(dataPromises);
console.log(...data);
}
getAandB();
I tried to edit my question but 'the edit queue was full'.
It took me a while to understand #Quentin's answer but I finally realized it relies on the fact that both instantiations of the callback function are altering the same variable (I think that is called by reference and is the default situation with arrays). Given this, although the instantiations know nothing about each other, it is possible to know when both ajax calls have completed by checking to see if the data array has been updated twice. If it has then both must have completed and data can be consoled out.
There is no need for the getAandB function. This much simpler and less confusing code works exactly the same as Quentin's answer:
<script>
const data = [];
function getA(){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
data.push(xhr.responseText);
if (data.length === 2){
console.log(...data);
}
}
}
xhr.send();
}
function getB(){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
data.push(xhr.responseText);
if (data.length === 2){
console.log(...data);
}
}
}
xhr.send();
}
getA();
getB();
</script>

What is the best way to do long polling in AJAX requests in JavaScript without JQuery?

hi after searching in the net about how to use the long polling in JavaScript I ended up with three ways, they are mentioned here briefly,but they are implemented using JQuery. I am confused which one to use in case that the AJAX request that I send to the server is asynchronous GET request ,and I don't know how many time it could take.
here is an example AJAX request:
function asynchGETRequest(method,url){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log("ok");
}
};
xhttp.open(method, url, true);
xhttp.send();
return (xhttp.responseText);
}
var clientFunctions={
getAnswers : function(callback){
var res=asynchGETRequest("GET", "http://localhost:9000/answers");
callback(JSON.stringify(res));
}
}
clientFunctions.getAnswers (function(){
//do some code here after the ajax request is ended
});
can some one guide me please?
I think I found the solution here
function loadFile(sUrl, timeout, callback){
var args = arguments.slice(3);
var xhr = new XMLHttpRequest();
xhr.ontimeout = function () {
console.error("The request for " + url + " timed out.");
};
xhr.onload = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
callback.apply(xhr, args);
} else {
console.error(xhr.statusText);
}
}
};
xhr.open("GET", url, true);
xhr.timeout = timeout;
xhr.send(null);
}

javascript: wait for a return

I have this problem.
I have a function for example called functionA() that needs the results from another function called functionB().
var globalVar="";
function functionA(){
//...
functionB();
//here i have to use the global variable (that is empty because functionB isn't finished)
}
function functionB(){
//ajax request
globalVar=ajaxRequest.responseText;
}
How can I do to let the functionB finish befor continue with the execution of functionA?
Thanks!
This is the code:
var ingredientiEsistenti="";
function ShowInserisciCommerciale() {
getElementiEsistenti();
JSON.parse(ingredientiEsistenti);
}
function getElementiEsistenti(){
// prendo gli ingredienti esistenti.
var url = "http://127.0.0.1:8080/Tesi/Ingredienti";
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("POST", url, false);
xmlHttp.send(null);
xmlHttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) // COMPLETED
{
if (xmlHttp.status == 200) // SUCCESSFUL
{
ingredientiEsistenti = xmlHttp.responseText;
} else {
alert("An error occurred while communicating with login server.");
}
}
};
}
You've got one of many options, that don't require an evil global variable:
Move the code you want to see executed to the onreadystatechange callback of the ajax request, that way, it won't get executed until you received a response
Redefine functionA, so that it takes a parameter that allows you to skip the first bit:
Make the request synchronous, not recommended, though
use a timeout/interval to check the readystate of the request manually (brute-force, not recommended either)
Perhaps there is some worker trickery that could do the trick, too, in your particular case
function functionA(skipDown)
{
skipDown = skipDown || false;
if (skipDown === false)
{
//doStuff
return functionB();//<-- call functionA(true); from the readystatechange callback
}
//this code will only be called if skipDown was passed
}
It is impossible to have a sleep/wait in JavaScript when the call is asynchronous. You need to use a callback pattern to make this action occur.
It is possible to make an XMLHttpRequest synchronous, but that can lead to other problems. It can hang the browser as it blocks all other actions from happening. So if you want to show a loading animation, it most likely will not execute.
You can make your AJAX request synchronous. https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Synchronous_and_Asynchronous_Requests
var request = new XMLHttpRequest();
// Last parameter makes it not asnychronous
request.open('GET', 'http://www.mozilla.org/', false);
request.send(null);
// Won't get here until the network call finishes
if (request.status === 200) {
console.log(request.responseText);
}
However, that will block the UI while waiting for the server to respond, which is almost never what you want. In that case, you should use a callback to process results.
Here's an example using a callback without relying on a global variable. You should always run away from those
function ShowInserisciCommerciale( ) {
getElementiEsistenti(function(responseText) {
JSON.parse(responseText);
});
}
function getElementiEsistenti(successCallback){
var url = "http://127.0.0.1:8080/Tesi/Ingredienti";
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("POST", url, false);
xmlHttp.send(null);
xmlHttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) // COMPLETED
{
if (xmlHttp.status == 200) // SUCCESSFUL
{
successCallback(xmlHttp.responseText);
} else {
alert("An error occurred while communicating with login server.");
}
}
};
}

XMLHttpRequest object not being instantiated?

I'm new to Ajax and this has me stumped. It's relatively simple but trips up on the onclick handler with the first xhr.open(). Firebug says it's not a function, my guess is the XMLHttpRequest object isn't being created, but I'm not sure. Anyone have any ideas?
Thanks in advance.
function init(){
function getXMLHTTP(){
var xhr = false;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
return xhr;
}
function updatePage(theData){
$('results').innerHTML = theData; //TODO: pretty this up with mootools
}
var xhr = getXMLHTTP();
if (xhr) {
xhr.onreadystatechange = function(){
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var theData = xhr.responseText;
updatePage(theData);
}
else{
alert("Error communicating to web service!");
}
}
}
$('submit_btn').onclick = function(xhr){
if ($('state').value != "") {
var theValue = $('state').value;
xhr.open("GET", "/inc/calc.php?state="+theValue, true); //Ajax 101: 3rd argument marks object as asynchronous
xhr.send(NULL);
}
else if ($('city').value != "") {
xhr.open("GET", "/inc/calc.php?city="+$('city').value, true);
xhr.send(NULL);
}
else if ($('county').value != "") {
xhr.open("GET", "/inc/calc.php?county="+$('county').value, true);
xhr.send(NULL);
}
else {
//the form is empty, or just down payment is filled. returns whole freakin' table.
xhr.open("GET", "/inc/calc.php", true);
xhr.send(NULL);
}
}
}
}
The problem with your code is the onclick function. You have put the xhr in the argument list to the function. Remember that when a function is called, the value of this variable is set by the caller. In this case it would be the event dispatcher, and it would probably set the xhr variable to an event object, which does not have an open function.
If you remove the xhr variable from the argument list of the onclick function, then it will look for the xhr variable in the parent scope, the global scope, and it will find it there, and it should work. I haven't tested it though.
I'm assuming you are using some kind of framework as well (judging by the frequent use of $, and the reference to mootools). This framework probably has an ajax function built in, as well as a cross browser event model. Try using it instead, you will run into a lot less problems.
When assigning the onclick handler you create a new function that takes a parameter called xhr:
$('submit_btn').onclick = function(xhr){
...
xhr.open("GET", "/inc/calc.php?state="+theValue, true);
...
}
The click on the button won't pass a XMLHttpRequest object the the handler, so xhr will not have an open() method. The global definition of xhr doesn't matter because it's shadowed by the local parameter definition.
Generally you should just generate a new local XMLHttpRequest object when you need it, not try to use a global one. For example use an onclick function that creates a new local XMLHttpRequest:
$('submit_btn').onclick = function(){
var xhr = getXMLHTTP();
xhr.open("GET", "/inc/calc.php?state="+theValue, true);
...
}

How to detect timeout on an AJAX (XmlHttpRequest) call in the browser?

I'm looking on the web, but documentation is hard to come by. We all know the basic AJAX call using the browser's built-in XMLHttpRequest object (assume a modern browser here):
var xmlHttp = new XMLHttpRequest(); // Assumes native object
xmlHttp.open("GET", "http://www.example.com", false);
xmlHttp.send("");
var statusCode = xmlHttp.status;
// Process it, and I'd love to know if the request timed out
So, is there a way that I can detect that the AJAX call timed out by inspecting the XMLHttpRequest object in the browser? Would I be advised to do something like window.setTimeout(function() { xmlHttp.abort() }, 30000);?
Thanks!
-Mike
Some of the modern browsers (2012) do this without having to rely on setTimeout: it's included in the XMLHttpRequest. See answer https://stackoverflow.com/a/4958782/698168:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
alert("ready state = 4");
}
};
xhr.open("POST", "http://www.service.org/myService.svc/Method", true);
xhr.setRequestHeader("Content-type", "application/json; charset=utf-8");
xhr.timeout = 4000;
xhr.ontimeout = function () { alert("Timed out!!!"); }
xhr.send(json);
UPDATE: Here's an example of how you can handle a timeout:
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", "http://www.example.com", true);
xmlHttp.onreadystatechange=function(){
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
clearTimeout(xmlHttpTimeout);
alert(xmlHttp.responseText);
}
}
// Now that we're ready to handle the response, we can make the request
xmlHttp.send("");
// Timeout to abort in 5 seconds
var xmlHttpTimeout=setTimeout(ajaxTimeout,5000);
function ajaxTimeout(){
xmlHttp.abort();
alert("Request timed out");
}
In IE8, You can add a timeout event handler to the XMLHttpRequest object.
var xmlHttp = new XMLHttpRequest();
xmlHttp.ontimeout = function(){
alert("request timed out");
}
I would recommend against making synchronous calls as your code implies and also recommend using a javascript framework to do this. jQuery is the most popular one. It makes your code more efficient, easier to maintain and cross-browser compatible.

Categories

Resources