I have an asynchronous audio upload script that works perfectly but there is one issue that is bugging me. The only thing it messes up is the error handling as an error is handled with an xhr status of 0 but there is seemingly no error as the upload continues.
xhr.upload.addEventListener("progress", keepPage(file,xhr),false);
xhr.upload.addEventListener("progress", uploadProgress,false);
xhr.upload.addEventListener("load", uploadComplete, false);
xhr.upload.addEventListener("error", uploadFailed(xhr.status), false);
xhr.upload.addEventListener("abort", uploadCanceled, false);
xhr.open("POST", "http://" + document.domain + "/script.php", true);
xhr.send(fd);
var uploading = true;
uploaded = false;
xhr.onreadystatechange=function(){
if (xhr.readyState==4 && xhr.status==200) {
var response = xhr.responseText;
if (response == "success"){
var uploaded = true;
processSuccess();
}
else {
var obj = $.parseJSON(response); //parse error JSON array
errReport = obj.errReport
uploadFailed(errReport);
}
}
}
uploading_tools(file, xhr, uploaded);
The error event is fired as soon as the script starts uploading. I have put console.log(xhr.status) in the uploadFailed function and a status of 0 is fired.
I understand an xhr status of 0 is given when an ajax is called across domains but as you can see this is not the case.
If I cannot get rid of this annoying bug I will just have to ignore an xhr status of 0 in my error handling which is something I would like to avoid doing.
Edit:
xhr.open("POST", "http://" + document.domain + "/script.php", true);
xhr.upload.addEventListener("progress", keepPage(file,xhr),false);
xhr.upload.addEventListener("progress", uploadProgress,false);
xhr.upload.addEventListener("load", uploadComplete, false);
xhr.upload.addEventListener("error", uploadFailed(xhr.status), false);
xhr.upload.addEventListener("abort", uploadCanceled, false);
xhr.send(fd);
var uploading = true;
uploaded = false;
xhr.onreadystatechange=function(){
if (xhr.readyState==4 && xhr.status==200) {
var response = xhr.responseText;
if (response == "success"){
var uploaded = true;
processSuccess();
}
else {
var obj = $.parseJSON(response); //parse error JSON array
errReport = obj.errReport
uploadFailed(errReport);
}
}
}
uploading_tools(file, xhr, uploaded);
Always call open() before accessing any other property or calling any other method of XMLHttpRequest. Strange behaviour can occur otherwise.
EDIt
I just saw the light, you are not getting an error!
You have this line:
xhr.upload.addEventListener("error", uploadFailed(xhr.status), false);
You aren't assigning uploadFailed() as the event handler for the error event. You are calling uploadFailed(xhr.status), so you are assigning as the event handler the return value of the function! Of course, surely uploadFailed does not return anything, so in the end you don't have an error handler. But, of course, when this line is executed your function is called! And as the call to xhr.send() hasn't occured yet, xhr.status is 0.
You have to change the line to
xhr.upload.addEventListener("error", uploadFailed, false);
Just like you have the others:
xhr.upload.addEventListener("progress", uploadProgress,false);
xhr.upload.addEventListener("load", uploadComplete, false);
NEW EDIT
In response to your comment, it doesn't work because you're doing the same you were doing, and not what I told you to do. Let's see if I can explain it to you.
Suppose your uploadFailed function is like this:
function uploadFailed(error) {
console.log(error);
return true; //you won't have this line, but let's assume you do.
}
Now, you have this code:
xhr.upload.addEventListener('error', uploadFailed(errReport), false);
Well, what is this line doing? Exactly this:
var f = uploadFailed(errReport); //uploadFailed is being called, not assigned to f
xhr.upload.addEventListener('error', f, false); //f is not a function, but the value 'true'!
Do you get it? When that line is executed, you are calling your function and assigning the result, not assigning the function itself. If your problem is how to pass the error value to the error function, you can do it this way:
function uploadFailed() {
console.log(this); //when you assign this function as an event handler,
//'this' will be the object which fired the event (xhr.upload)
}
You don't need to pass the xhr object to the function, but if, for whichever reason you need to pass the error as an argument, then you've got to do this:
xhr.upload.addEventListener('error', function() { uploadFailed(xhr.status); }, false);
This way you are defining a new function that has your xhr object in its scope and can pass it to your error function.
I hope you get the difference between a function and a function call, because it is essential.
Related
I am trying to run the following JS code locally on my computer as well as on codepen and in both places its returning me a status of 0, even though the link generated is perfectly fine. What can be the issue here? Have tried searching the net for cross-domain issues and have tried to set a NODE server/set headers explicitly to allow cross domain request, but nothing has worked till now.
window.onload = function(){
let search = document.querySelector('input');
const API_URL = "https://en.wikipedia.org/w/api.php?action=opensearch&format=json";
search.addEventListener('change', function(){
let term = this.value;
let url = `${API_URL}&search=${term}`;
console.log(url);
let xhr = new XMLHttpRequest();
xhr.onload = function(){
if(xhr.status === 200){
console.log("ok");
}
};
xhr.open('GET', url, true);
xhr.send(null);
console.log(xhr.status);
});
};
The xhr.status is available inside the onload method, status is only set after the onload method has been called.
xhr.onload = function(){
console.log(xhr.status);
if(xhr.status === 200){
console.log("ok");
}
};
Hi all,
var xhrDownloadImage = function (url, callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "blob";
xhr.onerror = function(e){console.log("Error: " + e)};
xhr.onabort = function(e){console.log("Abort: " + e)};
xhr.onload = function () {
console.log("onload");
var result;
if (xhr.status === 200) {
// image as blob
result = xhr.response;
} else {
result = null;
}
callback(result);
};
console.log(xhr.send());
};
I am calling the above function in a for loop,each time after executing the function i need to perform another function, say "function a". I use the xhr.response as the input of "function a".
But since it is async, it doesnt wait for the response and continues executing the loop. So i couldn't get the out put correctly.
I tried changing the XMLHttpRequest to sync. But in that case i get the following error:
Uncaught InvalidAccessError: Failed to set the 'responseType' property on 'XMLHttpRequest': the response type can only be changed for asynchronous HTTP requests made from a document.
How can i keep the 'XMLHttpRequest' async and do "function a" exactly after getting the response each time?
Please help,
Thanks.
That's what the callback is for:
xhrDownloadImage(url,a); // <--- this is how you call function "a"
Alternatively, if you have more than one function that you need to run after the download:
xhrDownloadImage(url,function(result){
a(result);
b(result);
some_other_function();
});
I would like to display a list when a user is typping text (like autocompletion).
I load a xml with the list and when the user is typping text, a javascript function loops into the xml to find matches.
Everything is ok except on Internet Explorer where it SOMETIMES displays this error : "SCRIPT65535: Invalid calling object".
The first time i call the js function to loop into the xml always works but if i wait 5 seconds before calling it again, it will dispay the error.
If i wait less than 1 second it won't display the error.
It may be because in the loop i call the getAttribute() method... when i remove it there is no error.
Thx for any help !
Here is the code :
Ajax loading :
var ajax = {};
ajax.getXMLHttpRequest = function(){
var xhr = null;
if(window.XMLHttpRequest || window.ActiveXObject){
if(window.ActiveXObject){
try{
xhr = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(e){
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
}
else xhr = new XMLHttpRequest();
}
else return null;
return xhr;
};
ajax.loadFile = function(callback){
var xhr = ajax.getXMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 0)){
callback(xhr.responseXML);
xhr = null;
}
};
xhr.open("GET", 'file.xml', true);
xhr.setRequestHeader("Content-Type", "text/xml");
xhr.send(null);
};
ajax.loadFile(callback);
Callback function :
var xml_nodes = '';
function callback(response){
xml_nodes = response.getElementsByTagName('node');
}
Then a mouseclick or whatever triggers this function :
function buttonClick(){
for(var i=0; i<xml_nodes.length; i++){
var attr = xml_nodes[i].getAttribute('attr');
}
}
This is a caching problem that only occurs in Internet Explorer. Your callback(response) function assigns the node elements to the xml_nodes variable. These nodes are a part of the response which is a part of the XMLHttpRequest, which gets disposed because you have no pointers to it.
The buttonClick function will iterate over the xml_nodes that are connected to disposed XMLHttpRequest's. And these are disposed because you have no pointers to it, and are therefore invalid objects.
A simple workaround will be caching your requests in an array. However this will result in large amounts of unwanted memory usage. You should create objects from the xml response and store them. These new objects won't have any pointers to the responseXML and are therefore valid objects.
Hope this helped, had the same problem to :)
I am writing a piece of code that should catch all ajax responses on a page. I managed to do this by overriding XMLHttpRequest.onreadystatechange for javascript direct ajax or by using ajaxComplete() for jQuery ajax.
My problem happens when I try to use ajax multiple times without creating a new XMLHttpObject, for example:
var xhr = new XMLHttpRequest();
xhr.open("GET", '/echo/json/', true);
xhr.send();
xhr.open("GET", '/echo/json/', true);
xhr.send()
This makes my code go haywire and I get the maximum stack error.
Here is my testing code on JSFiddle: http://jsfiddle.net/zxCfW/
var s_ajaxListener = {};
s_ajaxListener.tmpSend = XMLHttpRequest.prototype.send;
s_ajaxListener.callback = function () {
console.log('additional state change');
};
XMLHttpRequest.prototype.send = function() {
s_ajaxListener.tmpOnReadyStateChange = this.onreadystatechange;
this.onreadystatechange = function() {
if (s_ajaxListener.tmpOnReadyStateChange){
s_ajaxListener.tmpOnReadyStateChange.apply(this, arguments);
}
if(this.readyState == 4 && this.status == 200) {
s_ajaxListener.callback();
this.onreadystatechange = s_ajaxListener.tmpOnReadyStateChange;
}
};
s_ajaxListener.tmpSend.apply(this, arguments);
};
$(document).ajaxComplete(s_ajaxListener.callback);
I believe this happens because the ajax calls are asynchronous so the original onreadystatechange doesn't reset to its default value, but I don't know how to solve this.
Whenever I run this file the code runs up to the point where the send function fires and then it only fires if I have an alert function directly behind it, if I take out the alert("sent"); out then it replies with ServerReadyyState is:1.
What could possibly be the problem? Someone please help, I've tried it on my local machine and on my personal server and got the same results. Any help is greatly appreciated.
The Code:
/**
* #author d
*/
var xhr;
function getPlants(xhr) {
try {
xhr = new XMLHttpRequest();
} catch (microsoft) {
try {
xhr = new ActiveXObject("Msxml2.XMLHTTP");
} catch (othermicrosoft) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
xhr = false;
alert("ajax not supported");
}
}
}
xhr.open("GET", "db_interactions.php", true);
xhr.send(null);
alert("sent"); //the send function only works if this alert functions is here
if (xhr.readyState == 4) {
return xhr.responseText;
} else {
alert("Server ReadyState is:" + xhr.readyState);
xhr.abort();
//getPlants(xhr);
}
}
AJAX is asynchronus. You can't just check the ready state immediately after.
The correct design pattern is to assign a function for the AJAX call to run when the ready state changes.
xhr.onreadystatechange = function () { alert('It changed!') }
In that function, you'll want to check if the state is 4. If so, you're ready to process the output. If not, do nothing, since that function will be called a few times before the ready state is 4.
Requests take some amount of time. When adding an alert() the code is being stopped until the user clicks ok. So when you remove it the request is send and immedialty checked. Resulting in an unfinished request.
When you change your code to this:
xhr.onreadystatechange=state_change
xhr.send(null);
function state_change() {
if(xhr.readyState==4) {
return xhr.responseText;
} else {
alert("Server ReadyState is:"+xhr.readyState);
}
}
a certain function like in this case state_change gets called every time the state changes. So you can wait until the request is finished or until an errorcode comes up.