How to get the exact HTTP status code from onload event - javascript

On my server, some images take a long time to generate, but then are cached once they are generated, and so subsequent requests are quick.
Currently the server is returning a 202 Accepted HTTP status result when the image is still being generated. It returns a 200 result when the image is already generated can be sent immediately.
To avoid a web-page having a 'broken image' for a long time I have:
attached an event handler to the onload event of the image element, that will hide the image and display a placeholder image in its place if the server returned a 202 response.
if the image was not loaded with a 200 status start a periodic ajax rqeuest that will periodically check to see if the image is now available, and when it is show the image again.
However this system isn't working properly as I can't see how to tell 200 responses from 202 responses inside the onload event, and so can't tell when the ajax callback needs to be setup.
How can I determine what the status code of the response was that triggered the onload event was?
btw I've considered changed the response code for when the image is still being generated to be one that is considered an error, however the same issue would apply; how to tell the difference between a 'keep trying to load this image' and a genuine server error.

Instead of listening to the onload event, fetch the image with XHR and listen to the onreadystatechange event.
Here's an example: http://jsfiddle.net/DerekL/rwewrrod/
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
console.log("State: ", this.readyState, "Status: ", this.status);
if (this.readyState == 4 && this.status == 200) {
var url = window.URL || window.webkitURL;
document.querySelector("#img").src = url.createObjectURL(this.response);
} else if (this.readyState == 4) {
console.log(this.status);
} else {
//not ready yet
}
}
xhr.open('GET', 'image.png');
xhr.responseType = 'blob';
xhr.send();

It's looking a bit like this might be impossible to do as I originally asked. This is the hack that I'm using to workaround not being able to get the status codes.
Change the server to return a status code that indicates an error when the image is still being generated. I choose 420 - 'Enhance your calm'.
Make the callback for starting the Ajax asynchronous be listening to the 'onerror' event.
So now, if the image is loaded okay by the browser, no callbacks are called at all, and the image is displayed as soon as possible.
If the initial image request fails, the ajax stuff gets started. Because in the initial onerror callback, we can't tell the difference between actual server errors and the 420 'Image is still being generated' error, this means that there will be duplicate requests when there is an error.....but that is a rare occurrence, and we don't care about having an error delayed by a second.

Related

JS style-changes don't get applied when inside request

I want to make it such that an image on a website gets its "onclick" event disabled and a gray filter applied, if a certain file on the same domain is not found. I want to use purely JS and have tried this so far:
function fileNonExist(url, callback){
var http = new XMLHttpRequest();
http.onreadystatechange = function() {
if (http.readyState === XMLHttpRequest.DONE && callback) {
if(http.status != 200){
callback();
}
}
}
http.open('HEAD', url);
http.send();
}
fileNonExist("theFileIAmLookingFor.html", () => {
console.log("image changed");
image.onclick = "";
image.style.filter = "grayscale(100%)";
});
I have the image initialized and displayed. Thus image.onclick = "" and image.style.filter = "grayscale(100%)
both work, if they are used normally. However, even though the function blocks are executed as intended (Console logs "image changed" if the file isnt found, and nothing otherwise.) none of the style changes are ever visible, if they are executed from within those blocks. Why might that be and how could I fix it?
I found out the solution myself, while talking to Emiel Zuurbier: I noticed that the code works if I open the html file normally in my browser. The bug occurs, if I access the file over a webserver, which i've done the whole time. If I shut down the server while the site is still opened in the browser, then the changes also get applied. If I look at the requests with dev tools in the browser. I see that only the successfull requests are finishing and the unsuccessfull ones are left pending forever. Thats why the changes get applied when the server is shut down and all pending requests get closed with errors. The Server uses the Node.js "fs" module and its readFile method.
I will now try to turn the styles around so all images start off gray and without "onclick" - methods and only become unlocked once the file is found. This way the images with pending requests remain gray.

Detecting start and stop of xhr request

I'm using a wysiwyg editor called summernote. This editor exists as an iframe within my application.
The editor accepts images and upon inserting an image into the editor, the image automatically starts to upload to my s3 bucked on aws. I've looked at the source code for django-summernote and I can't seem to see any references to ajax, so I'm not sure if it uses that or another technology.
What I do know is that during the upload process, an xhr request in initiated and remains active for the duration of the upload.
As soon as the user drops an image in the editor (and the xhr request starts), I'd like to show a spinner/loading icon so that they are aware that something is happening. I'd like the spinner to disappear once the xhr request has completed.
Is there a way that I can have javascript listen for any xhr requets and fire an event when one starts and when it ends?
Thanks!
Edit: Paul has indicated that I can use these:
var xhr = new XMLHttpRequest();
console.log('UNSENT', xhr.readyState); // readyState will be 0
xhr.open('GET', '/api', true);
console.log('OPENED', xhr.readyState); // readyState will be 1
xhr.onprogress = function () {
console.log('LOADING', xhr.readyState); // readyState will be 3
};
xhr.onload = function () {
console.log('DONE', xhr.readyState); // readyState will be 4
};
xhr.send(null);
Do I need to poll for the XMLHTTPRequest() every second and then check its status or is there a cleaner way to do this?
Thanks!

XMLHttpRequest returning with status 200, but 'onreadystatechange' event not fired

We have been receiving an intermittent bug with the XMLHttpRequest object when using IE11. Our codebase is using legacy architecture, so this browser is required.
After clicking a button, the browser launches an out-of-band process by creating a new ActiveX control which integrates with a camera to capture an image. This control appears to be working fine... it allows the operator to capture the image, and the Base64 content of the image is returned out of the control back to the browser interface, so I think we can rule out a problem with this object.
Once the image is returned to the browser, the browser performs an asynchronous 'ping' to the web server to check if the IIS session is still alive or it has expired (because the out-of-band image capture process forbids control of the browser while it is open).
The ping to the server returns successfully (and running Fiddler I can see that the response has status 200), with the expected response data:
<sessionstate>ok</sessionstate>
There is a defined 'onreadystatechange' function which should be fired on this response, and the majority of times this seems to fire correctly. However, on the rare occasion it does appear, it continues to happen every time.
Here is a snippet of the code... we expect the 'callback()' function to be called on a successful response to Timeout.asp:
XMLPoster.prototype.checkSessionAliveAsync = function(callback) {
var checkSessionAlive = new XMLHttpRequest();
checkSessionAlive.open("POST", "Timeout.asp?Action=ping", true);
checkSessionAlive.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
checkSessionAlive.onreadystatechange = function() {
if (checkSessionAlive.readyState == 4) {
if (checkSessionAlive.responseText.indexOf("expired") != -1 || checkSessionAlive.status !== 200) {
eTop.window.main.location = "timeout.asp";
return;
}
callback(checkSessionAlive.responseText);
}
}
checkSessionAlive.send();
}
Has anyone seen anything like this before? I appreciate that using legacy software is not ideal, but we are currently limited to using it.

Not Receiving Asynchronous AJAX Requests When Sent Rapidly

My script is sending a GET request to a page (http://example.org/getlisting/) and the page, in turn, responds back with a JSON object. ({"success":true, "listingid":"123456"})
Here's an example snippet:
var listingAjax = new XMLHttpRequest();
listingAjax.addEventListener("load", listingCallback, false);
function listingCallback(event) {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
}
listingAjax.open("GET", "http://example.org/getlisting/", true);
listingAjax.send();
Simple enough. The script works perfectly too! The issue arises when I want to do this:
var listingAjax = new XMLHttpRequest();
listingAjax.addEventListener("load", listingCallback, false);
function listingCallback(event) {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
}
window.setInterval(function() {
listingAjax.open("GET", "http://example.org/getlisting/", true);
listingAjax.send();
}, 250);
What I imagine should happen is my script would create a steady flow of GET requests that get sent out to the server and then the server responds to each one. Then, my script will receive the server's responses and send them to the callback.
To be more exact, say I let this script run for 5 seconds and my script sent out 20 GET requests to the server in that time. I would expect that my callback (listingCallback) would be called 20 times as well.
The issue is, it isn't. It almost seems that, if I sent out two GET requests before I received a response from the server, then the response is ignored or discarded.
What am I doing wrong/misunderstanding from this?
Many browsers have a built in maximum number of open HTTP connections per server. You might be hitting that wall?
Here is an example from Mozilla but most browsers should have something like this built in: http://kb.mozillazine.org/Network.http.max-connections-per-server
An earlier question regarding Chrome:
Increasing Google Chrome's max-connections-per-server limit to more than 6
If you have Windows, take a look at a tool like Fiddler - you might be able to see if all of the requests are actually being issued or if the browser is queueing/killing some of them.
You can't reuse the same XMLHttpRequest object opening a new connection while one is in progress, otherwise it will cause an abrupt abortion (tested in Chrome). Using a new XMLHttpRequest object for each call will solve that:
function listingCallback(event) {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
}
window.setInterval(function() {
var listingAjax = new XMLHttpRequest();
listingAjax.addEventListener("load", listingCallback, false);
listingAjax.open("GET", "http://example.org/getlisting/", true);
listingAjax.send();
}, 250);
This will work nicely queueing a new ajax request for each interval.
Fiddle
Note that too frequent calls may cause slowdown due to the maximum limit of concurrent ajax calls which is inherent to each browser.
Though, modern browsers have a pretty fair limit and very good parallelism, so as long as you're fetching just a small JSON object modern browsers should be able to keep up even when using a dial-up.
Last time I made an ajax polling script, I'd start a new request in the success handler of the previous request instead of using an interval, in order to minimize ajax calls. Not sure if this logic is applicable to your app though.

How to determine error code on broken images with mootools

I need a script that can determine the reason an image didn't load based on the HTTP status code supplied.
I am aware of the onError event on images and objects, but it does not pass the error code. So if an image has a broken source or a time out occurred are dealt with the same way.
What I would like is to have a script that can determine the error code and act accordingly.
For example:
404 - replace image with a predefined one
403 - notify admin using an callback function
504 - try to reload
etc.
I've done some searching on google, but other than the onError event I came up short.
Any ideas?
the only thing i can think of is to go to a xhr request on fail, with Asset.image from more handling the loading:
new Asset.image('foo.jpg', {
onload: function() {
someel.adopt(this);
},
onerror: function() {
new Request({
url: this.get('src'),
onComplete: function() {
console.log(this.status); // 404
}
}).get();
}
});
http://jsfiddle.net/dimitar/2hwej/
not exactly the greatest as it would mean 2 requests. to go around that, you can put your image loading into a xhr request to begin with and then use base64 data to output or something.

Categories

Resources