variabled passed through async function is changing when i call it twice - javascript

i have an async httprequest seen below
function httpGet(URL, type, daily, weekly, monthly)
{
if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();
}
else
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
if (type == 'table')
{
createTable(xmlhttp.responseText, daily, weekly, monthly);
}
}
}
xmlhttp.open("GET", URL, true);
xmlhttp.send();
}
When i call it twice for example
httpGet('example', 'table', 1, 2, 3);
httpGet('example2', 'table', 4, 5, 6);
They will both return the results from the second URL. Im sure making the function not async will fix this but thats not very user friendly either.
Is there anyway to set in stone the url i want to return as the one passed in the parameter that originally called it instead of last called it

You aren't declaring xmlhttp with const, let, or var - this means that it will be a global variable, so each call to httpGet will result in the reassignment of the global variable, rather than each function having a separate binding for xmlhttp. So, when the last line in there runs:
createTable(xmlhttp.responseText, daily, weekly, monthly);
the xmlhttp there will always be referring to the final xmlhttp.
Change your code to:
function httpGet(URL, type, daily, weekly, monthly) {
const xmlhttp = window.XMLHttpRequest
? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange = function() {
// ...
to ensure that each call gets a separate binding of xmlhttp.
Also, you might consider using fetch and ditching ActiveXObject - ActiveXObject should only be needed for supporting IE6 and below, which are broken browsers that probably shouldn't be considered at all.

Related

why ajax value return is undefined with settimeout? how do I fix it?

I got two AJAX functions that I need to call when the HTML body onload. The function need to operated at separated time interval for different type of chat so I can soften the work load on the server.
(please no JQuery)
function funcNamePOST(data1, data2) {
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function(){
//Appending xml data to html in a for loop
}
var date = new Date();
var datetime = date.getTime();
xmlhttp.open("POST", "page1.php", true);
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
var parameters = "data1="+data1+"&data2="+data2;
xmlhttp.send(parameters);
}
function funcNameGET(data1, data2) {
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function(){
//Appending xml data to html in a for loop
}
var date = new Date();
var datetime = date.getTime();
xmlhttp.open("GET", "page2.php?datetime="+datetime, true);
xmlhttp.send();
}
Both of these AJAX works fine on there own, but this get strange then I try to nest them and/or add them to a time functions.
Example:
function nest(data1, data2) {
funcNamePOST(data1, data2);
funcNameGET(data1, data2);
}
OR
function nest(data1, data2) {
setTimeout( function(){
funcNamePOST(data1, data2);
}, 10000);
//I need this to run every 10 sec
setTimeout( function(){
funcNameGET(data1, data2);
}, 60000);
//I need this to run every 60 sec
}
Only the second AJAX in the nest execute. It Doesn't matter which order the function is in the nest, and then it output an error on the first function.
TypeError: AJAX "XML value" return is undefined.
I know that not true because they work fine on their own.
The only way I got it to work was to put them inside timed functions, but I can't get get the first function to run every 10 sec this way.
function nest(data1, data2) {
setTimeout( function(){
funcNamePOST(data1, data2);
setTimeout( function(){
funcNameGET(data1, data2);
}, 60000);
}, 10000);
}
Your functions are sharing a single global variable called xmlhttp. Declare that variable separately in each function with var:
var xmlhttp;
What's happening now is that each function is "stepping on" the other one when it's called by overwriting the value of xmlhttp. By making two local variables instead, that can't happen.
One good way to catch problems like this (at least in newer browsers) is to get in the habit of adding
"use strict";
as the very first line of code in each function, or if possible as the first line of code in the whole script block. If you do that, you put the interpreter in "strict" mode, and in that mode it would have flagged the assignments to xmlhttp as erroneous.

AJAX callback is super-slow?

I'm experimenting a bit with AJAX and have successfully deployed a simple AJAX A-synced function, yet when I'm changing it to use callback method - suddenly, it takes ages to load (about 10 - 15 mins...).
Here's the function that executes right away:
function ajaxf() {
var xmlhttp;
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200 && document.getElementById("icons")==null)
{
document.getElementById("text-12").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","http://some-url/ajax.php",true);
xmlhttp.send();
}
And here's the way slower iteration using a callback function:
function ajaxf(url,cfunc) {
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=cfunc;
xmlhttp.open("GET",url,true);
xmlhttp.send();
}
document.body.onscroll = function ajaxb() {
ajaxf("http://some-url/ajax.php",function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200 && document.getElementById("icons")==null)
{
document.getElementById("text-4").innerHTML=xmlhttp.responseText;
}
});
}
Other (perhaps) relevant details - the ajax.php file weighs merely 532 B, on my local test server both run more or less equally the same, the first function uses onscroll="ajaxf()" inside the body tag...
I was under the impression AJAX would be a little more snappy???
I solved it, thanks to #jasen's tip I've put a console.log() and was able to see the scroll function fiered a gazillion times just like #jfriend00 said.
Initially, I thought that by putting "document.getElementById("icons")==null" as a condition - the function would only fire once but I was wrong of course,
So the solution was / is:
to reset the onscroll action after the first execution by adding "document.body.onscroll = null;" at the end of the function.

Giving an attribute to an xmlhttprequest object

I have the following code :
<head>
<script>
function startChanging() {
var elems = document.getElementsByTagName("img");
for(var i=0; i < elems.length; i++)
{
var xmlhttp;
if (window.XMLHttpRequest)
{
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp["elem"] = elems[i];
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
this["elem"].src = xmlhttp.responseText;
}
}
xmlhttp.open("GET", "http://myurl.com/somescript.php", true);
xmlhttp.send();
}
};
</script>
</head>
<body onload="startChanging()">
<img src="https://www.google.com/images/srpr/logo11w.png">
<br/>
<img src="https://www.google.com/images/srpr/logo11w.png">
<br/>
<img src="https://www.google.com/images/srpr/logo11w.png">
</body>
Even though I create a new instance of XMLHttpRequest for each iteration and add the current element to an attribute, when the request returns a response only the last img element is changed.
I am looking for a simple solution to change the src of the img element without iterating through all the elements again when the response comes. I would like a pure Javascript solution (read: no JQuery).
I am certainly doing something wrong here I just don't understand what. Any help would be appreciated.
In your for loop, you are overwriting the xmlhttp variable so when you get into the onreadystatechage function and you check the value of xmlhttp.readyState, it will not be checking the right object.
I'd suggest this fix which changes two things:
It puts each ajax call into it's own IIFE which keeps the xmlhttp variable separate for each ajax call.
It passes elems[i] into the closure so you don't have to do the property saving hack.
Code:
function startChanging() {
var elems = document.getElementsByTagName("img");
for(var i=0; i < elems.length; i++)
{
(function(obj) {
var xmlhttp;
if (window.XMLHttpRequest)
{
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
obj.src = xmlhttp.responseText;
}
}
xmlhttp.open("GET", "http://myurl.com/somescript.php", true);
xmlhttp.send();
})(elems[i]);
}
};
One possible approach:
xmlhttp.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
this.elem.src = this.responseText;
}
}
As you see, I've replaced all the references to xmlhttp within that handler function to this.
The problem is even though you've created a new AJAX-serving object at each step of the loop, each newly-created 'readystatechange' handler function referred to the same object known under xmlhttp variable.
In general, this is quite a common problem when someone works with a variable declared within a loop yet referred by functions created in the same loop. Stumble upon this once or twice, and you'll begin to see the pattern. )
xmlhttp.send();
Put data into the send method:
xmlhttp.send(data);
Source: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
void send();
void send(ArrayBuffer data);
void send(ArrayBufferView data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);
Where data is a JavaScript variable, you can put anything into. If you want multipart message, you'd use var data = new FormData(); and put data into it using data.append('image', file); for file upload via ajax for example.
If no multipart, simply put anything in like:
data = { images: document.getElementsByTagName("img") }

Ajax request to load .php file not working

Trying to load contents from postcode.php file into a #postcodeList div, but it is not working (nothing happens). I checked postcode.php file it echoes al correct information.
var loadicecream = document.getElementById("iceCreams");
loadicecream.addEventListener("click", iceAjax, false);
function iceAjax() {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("POST","ice-cream-list.php",true);
xmlhttp.send();
document.getElementById("ice-cream-list").innerHTML = xmlhttp.responseText;
}
You want the query to execute asynchronously (the third parameter to open function) and then you synchronously try to read the value. This happens before the query has been sent, so it will always be empty.
Either run the load synchronously, or set the xmlhttp.onreadystatechange to point into a function where you handle the loaded state. The best way is to do it asynchronously since you don't want to block the user from using the page while loading data.
Quick example, only handles the success case:
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
document.getElementById("postcodeList").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("POST","postcode.php",true);
xmlhttp.send();
Read up on the documentation for the onreadystatechange, at least you want to handle the case where there is a timeout or some error, otherwise the user won't know something went wrong.

AJAX: head and more

For asynchronous quick-checks of an URL, I use AJAX with method=HEAD:
function ajax_quickresponse(url) {
var xmlhttp = null;
if (window.XMLHttpRequest)
xmlhttp = new XMLHttpRequest();
else if (window.ActiveXObject)
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
if (xmlhttp) {
xmlhttp.open("HEAD", url, true);
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4) {
if ((xmlhttp.status > 199 && xmlhttp.status < 400))
; //OK
else
; //ERR
};
};
xmlhttp.send(null);
};
};
This receives is enough for checking the http status, but seems to abort the script at serverside (url). E.g. I can try with a simple php script (url="http://my-host.er/test/script.php") which does sleep(2); and log a success message afterwards.
With xmlhttp.open("HEAD", url, true);, there is no success entry in the log.
With xmlhttp.open("GET", url, true);, there is a success entry in the log.
However, with GET/POST, the javascript is waiting 2 seconds instead of instantly (with HEAD).
The status is known instantly and the javascript does not need to wait for the final response.
How to take advantage of both methods? First, I need the status instantly, as soon as the header comes in, and after the external url/script returns, then i'd like another listener.
E.g. first alert('http status='+xmlhttp.status); and maybe delayed, depending on the url/script, alert('finally completed');
Do you have a tip how to achieve this with one single call?

Categories