Detecting start and stop of xhr request - javascript

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!

Related

Why should we put onload before send method

I am new to JavaScript and would like to ask about about AJAX, that is, why we put xhr.onload before xhr.send() since even if I put xhr.onload after xhr.send() all works perfectly. But majority of tutorials teach you to put onload before send() without proper explanation. So, should I use
let btn = document.querySelector('button').addEventListener('click', function(){
let xhr = new XMLHttpRequest();
xhr.onload=function(){
if(this.status===200){
let div=document.querySelector('div').innerHTML=xhr.responseText;
}
}
xhr.open('GET', './mir.txt');
xhr.send();
})
Or
let btn = document.querySelector('button').addEventListener('click', function(){
let xhr = new XMLHttpRequest();
xhr.open('GET', './mir.txt');
xhr.send();
xhr.onload=function(){
if(this.status===200){
let div=document.querySelector('div').innerHTML=xhr.responseText;
}
}
})
and WHY?
Use your first version.
Logically, in the situation where the browser has the response cached, then XHR could complete instantly, and then you try to add "onload" after the response has already loaded, then nothing will happen.
In reality, even when cached, I don't think this can happen because of how the browser engine works, but from the coding point of view, it looks like it could happen. So making the pattern have onload at the top removes all suspicion that such behaviour could occur. Possibly in older browsers, when people did tend to do XHR reuests manually, that kind of thing was an actual danger?
I do know, in the scenario where you syncronously load a request, it does matter, because the thread will be blocked (as well as the whole window) during the send until it completes.
Onload is most frequently used within the element to perform a script once a website has fully loaded (including script files, images, CSS files, etc.) So Its a good approach lets load all the dependency after that we make a API call or Ajax call to update our DOM.
You don't have to use onload() before send(), your first and second example shows that already.
onload() is an event of XHR Object (a property for the load event of XHR), so it'll execute automatically when a particular event satisfies during the XHR execution. The function called when an XMLHttpRequest transaction completes successfully. So, Using onload() property you just define/tell what needs to do when load event satisfied. You don't have to define if you don't need it.
send() is a method of XHR, not an event. so you need to call it if you want it. see reference link to see more about its behavior for synchronous and asynchronous call.
Ref:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload

Why xmlhttprequest functions open() & send() are located at the end of the function

I've been teaching myself php and xml (among other languages) and while going through the xmlhttprequest tutorial on w3schools, I noticed the open() and send() functions are located at the end of the function and not before or out of it. This is a bit puzzling because how can one get a response from the server if the request has not yet been sent? It maybe be something simple that I have missed and I apologize if that's the case but can anyone help me with my dilemma? Thanks in advance
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = this.responseText;
}
};
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();
}
The code to read the data will be in a separate function that is assigned as an event handler.
That function won't run until the response is received.
Related: How do I return the response from an asynchronous call?
It probably doesn't matter on modern browsers, but fundamentally, it's so you set up the call before sending it. In particular, so that all the handlers have been attached before asking the XHR to do something. Compare:
// Example 1
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", function() {
// Got the data
});
xhr.open("GET", "http://example.com");
xhr.send();
with
// Example 2
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com");
xhr.send();
xhr.addEventListener("load", function() {
// Got the data
});
Browsers are not single-threaded, though they run JavaScript code in a single main thread (plus any web workers you create). So it's possible (though extraordinarily unlikely) that with Example 2, if the resource is in the browser's cache, a separate thread handling network calls could trigger the load event between the send and addEventListener calls on the JavaScript thread, see that there were no handlers registered, and not queue a task for the event loop to call the handler. Whereas with Example 1, if it triggers the load event immediately upon send, it sees an attached handler and queues a task to call it (which runs later, when the event loop comes around to processing that task).
Here's an example of that hypothetical scenario, showing the thread interaction:
Example 1 - Highly Theoretical Scenario
JavaScript Thread Network Thread
----------------------------------------- --------------
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", function() {
// Got the data
});
xhr.open("GET", "http://example.com");
xhr.send();
(Within send: Start the send, handing
off to the network thread)
1. Start a GET on `xhr`
2. It's in cache, are there any load
handlers registered on `xhr`?
3. Yes, queue a task to call the handler
(Done with current task)
(Pick up next task)
Call the handler
vs
Example 2 - Highly Theoretical Scenario
JavaScript Thread Network Thread
----------------------------------------- --------------
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com");
xhr.send();
(Within send: Start the send, handing
off to the network thread)
1. Start a GET on `xhr`
2. It's in cache, are there any load
handlers registered on `xhr`?
3. No, don't queue a task to call
the handler
xhr.addEventListener("load", function() {
// Got the data
});
(Done with current task)
(Pick up next task)
(No task, do nothing)
I very much doubt any current browser would actually do that (Example 2), and I'm not aware of XHR having had a problem like this in the past. But it's theoretically possible, and there was a very similar problem, circa 2008, with setting src on an img element before hooking the load event for it. However, browsers fixed that problem, and I'd be surprised to find they were open to the Example 2 scenario above now, either, even if they or may not have been at some point in the past.
In practice, I doubt it matters. But I'd still use Example 1 if I used XMLHttpRequest (I don't, I use fetch).

Chrome Extension interact with page (not in tab) in background

How can I make a extension that interact with a page in background (not in tab)? for example check www.google.com each 5 minutes while I have only www.yahoo.com open.
I have made the function of the extension but I need to know how to use it without having this page open.
Regards.
Saying you want to interact with https://www.google.com without opening it, you could make an ajax call in background page. Steps would be like the following:
Add https://www.google.com/* in permissions field in manifest.json
"permissions": ["https://www.google.com/*"]
Make an ajax call in background page.
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var data = xhr.responseText;
// Your logic to handle response data
};
xhr.open("GET", "https://www.google.com");
xhr.send();

How to get the exact HTTP status code from onload event

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.

Call to xmlhttprequest from page onload event is not working OK when Back from another page

After going from my page to anther page by pressing a link, and than back to current page, than in call to xmlhttprequest from onload event, The js code of xhr.open and xhr.send is working, but the sever side code called by xhr is not running, and in xhr.onreadystatechange function the xhr.responseText is returning his old value.
In this scenario off comming back from another page, call to xmlhttprequest from document.onreadystatechange event is also not working OK.
The same code works OK when I call it from onload in the first page loading (before going to another page and returning), or when I call it from a button click.
Why the call to xmlhttprequest from onload event is not working OK when Back from another page?
I'm using Chrome.
Here is my code:
<script type="text/javascript">
function CallAJAX() {
xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
xhr.onreadystatechange = AJAX_onreadystatechange;
xhr.open("GET", '/MyPage.aspx', true);
xhr.send(null);
}
function AJAX_onreadystatechange() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert('xhr.responseText=' + xhr.responseText);
}
}
window.onload = function () {
//alert is working also after going to link and than back to current page
alert('alert')
//Call to xmlhttprequest from page onload event - is Not working OK - after going to link and than back to current page
CallAJAX();
}
</script>
<!--here is the "link" mentioned in the above comment-->
link
<!--Call to xmlhttprequest from button onclick event - is working OK-->
<input id="Button1" type="button" value="button" onclick="CallAJAX();" />
Update
I found the problem:
In some browsers, and in some circumstances, xhr brought the xhr.responseText
value from browser cache, instead to call server.
Here is the solution:
This problem solved by adding unique query string param to url param of xhr.open. This guaranty that the ajax will avoid using the cache, and always hit the server, because with the unique param, the url is turned to unique in every call to xhr.open.
The unique value is produced by "new Date().getTime()" which returns the number of milliseconds between midnight of January 1, 1970 and now.
This is the solution code:
xhr.open("GET", '/MyPage.aspx?uniqueParamVal=' + new Date().getTime(), true);

Categories

Resources