Javascript: Cancel/Stop Image Requests - javascript

I have a website that makes heavy use of Ajax. Occasionally I need to load large image files on the page for the user. My question is, when these large image files are being download, is there a way to stop them if, say, the user navigates away from the page displaying the image? Thanks.

I had the exact same issue, when users 'paged' quickly through (ajax) search results the browser was still trying to download profile images for every page not just the current one. This code worked for me, called on the paging event just before the new search was run:
//cancel image downloads
if(window.stop !== undefined)
{
window.stop();
}
else if(document.execCommand !== undefined)
{
document.execCommand("Stop", false);
}
Essentially it's like clicking the "Stop" button on the browser.
Tested in IE, FireFox, Chrome, Opera and Safari

like this.
$(img).attr('src','');

Assuming that you are using ajax to load the images, you could simply abort the request in the window.onunload event. Declare a global variable for the XMLHttpRequest object that you are using.
var xhr;
//if using the XMLHttpRequest object directly
//you may already be doing something like this
function getImage(...){
xhr = new XMLHttpRequest();
xhr.open(....);
}
if using jQuery, you could assign the return value of the call you $.ajax() or $.get to xhr variable.
xhr = $.ajax(.....);
Handle the window.onunload and abort the request.
window.onunload = function(){
xhr.abort();
}

Reassigning the SRC tag to a different image does not work in IE7, it continues trying to download the first image.
Here is the setup:
I created an HTTP handler that is of type JPEG. It contains code that never finishes executing. So someImage.src=myhandler.ashx will perpetually sit there loading until it times out.
In the middle of this, press another button that reassigns the image to a small image file:
someImage.src=small.jpg
The request for myhandler.ashx does not end, even though we have reassigned the src.
Furthermore if you actually delete the node someImage.parentNode.removeChild(someImage) is still keeps trying to download myhandler.ashx
Tested with IE7 and monitored with HTTP Watch Pro.

The poor mans solution would be to simply set the SRC property of the image tag to an empty string, or point it towards a widget.
edit
Saw your comment, surprised it doesn't work with changing the SRC property to empty... try using a blank.gif or something.
If that doesn't work, you may be bounded by browser architecture, meaning you are S.O.L.

Related

Is there a way to edit a javascript function back to the original?

So I had this code here which overwrites the default canvas.toDataURL() function and makes it return something different.
HTMLCanvasElement.prototype.toDataURL = function () {
return "data:image/png;base64," + thing;
}
And I was thinking if there was any way to restore the toDataURL function back to how it functions normally either through updating it again or deleting the lines of code?
So I was thinking of executing some code like:
HTMLCanvasElement.prototype.toDataURL = function () {
//original code for toDataURL
}
This code is for a page that already exists on the internet so this line of code is run before I can delete it.
Things I have tried:
Using Google Chrome's Developer Tools > Sources > Deleting the line from the javascript code > Ctrl + S to save the javascript > Trying to call the function .toDataURL(), however, toDataURL() still performs the modified version rather than what I want which is the original version.
I suspect this is because I am not properly saving the changes as the changes to the toDataURL() function are in an external Javascript file.
I have also looked into using fiddler 4 with google chrome, but I'm not having much luck on that end, despite having created breakpoints every time a javascript file should be added. This is with the intention of stopping the execution of the code, giving me time to edit the javascript file before it runs.
I have created breakpoints in fiddler 4 by making the following changes for the code in the custom rules:
static function OnBeforeResponse(oSession: Session) {
if (m_Hide304s && oSession.responseCode == 304) {
oSession["ui-hide"] = "true";
}
if (oSession.oResponse.headers.ExistsAndContains("Content-Type", "javascript")){
oSession["x-breakresponse"]="reason is JScript";
}
}
The error which occurs is Google Chrome does not pause on a breakpoint like it is supposed to once I load the page which loads the changes for the toDataURL() in an external JS file thus, I cannot edit the Javascript files to delete the lines of code before they are executed.
The breakpoints still happen but at the wrong times for example when I click on the Google Chrome address bar.
And despite adding a breakpoint the link itself for the specific external javascript file to fiddler with the command:
bup https://url/changeFunction.min.js
The breakpoint does not happen, thus, not giving me the chance to edit the file.

Hitting a url better?

I've a ashx handler which outputs the file, when pinged.
As of now, I have it working by
window.open('url to ping');
I'm happy with the result. But however I'm interested in a better solution, since a user might have turned on popup blocker, which might result in file not downloading.
I can also use jquery ( if that helps )
You can simply use window.location = "http://pathtoyourhandler.ashx" instead.
With appropriate Content-Type the browser will stay on the current page and begin downloading the requested file.
If you do not want a window to open, you could always create a hidden <iframe> that has it's src property set to your link.
We used that work around when simply setting the location did not give the expected result (at least in IE8).
DEMO

How to cancel an image from loading

Suppose in Javascript that you assign the SRC to an IMG tag. It is a large SRC and you want to cancel it before it has finished loading. Assigning the SRC to another image will not stop the data from loading.
That is, in the middle of the load you can assign the SRC to another smaller image and the smaller image will be loaded and appear in your browser. However, the original SRC still continues downloading.
Similarly, deleting the IMG node will not prevent the SRC from continuing to download. No guesses please, look at the repro steps.
REPRO
Load this URL in Chrome in Windows: http://68.178.240.17/imgLoadTest/imgLoadTest.htm
Open up the developer panel by pressing CTRL-SHIFT-J
On the top row of icons in the Chrome developer panel click the Network icon to watch network activity.
On the web page loaded in Step 1 click the Load Image button and watch the developer panel as a large (32meg) image starts loading.
On the web page click the Try To Cancel button to load a different image.
A small image loads, but watch the network in the developer panel and notice that the large image continues to download.
Quick answer
Setting the src attribute of the img tag to the empty string will interrupt the current download, even on Chrome.
Details
Nowadays most of browsers implemented that out-of-standard mechanism thought in the old answer to programmatically abort the connection. This is not achieved through a protocol request, but with a client-side in-memory operation. Keep in mind that is not a standard behaviour, but most of vendors courtesy. That is, it could not work on every browser.
I've prepared a jsfiddle showing this mechanism in action (keep an eye at the network panel of the inspector).
Old answer (2011)
Your browser asks for that image with a specific HTTP GET request, as specified in HTTP protocol. Once it asks for it, the http server starts the transfer.
So, it is between the browser (as http client) and the http server.
Since http protocol does not takes into account the option to abort a transfer, the browser should implement a out-of-standard mechanism to programmatically abort the connection. But since this is not specified in any standard, i think you won't find any way to do that with javascript or any client side code.
Cancel with transparent base64 encoded GIF to avoid additional requests and double page load on android:
var img = new Image();
img.src = 'http://google.com/favicon.ico';
img.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEAAAAALAAAAAABAAEAAAI=;'
Although I can't find the bug report now, I believe this is a long-standing logged WebKit bug. Firefox (and IE I think) have more sane behavior. I'm going back a bit in my brain, but if I recall on those browsers, resetting the img.src will in fact cancel outstanding downloads. I am positive that Firefox does this when a download is "waiting in line" for a chance at an open HTTP connection, and I seem to recall that it will actually force close connections sometimes.
I've never found a way to coax WebKit based browsers into cancelling an img download in progress, whether it is just queued or already actively downloading.
This really sucks if you're making something like a mapping client and need more fine grained control over images.
Setting the .src property to an empty string should cancel the load:
//load image from url
var img = new Image();
img.src = 'http://somedomain.com/image.jpg';
......
//cancel load
img.src = '';
Yes, page is downloaded twice on Android when an img tag has an src="" attribute.
This still occurs on recent Android versions.
I have not found any other browser that does that.
But I found a solution: use an img tag without src attribute.
The ultimative answer is web workers.
Load the image inside an webworker and stopping the web worker will stop the image loading.
You can get the idea from this code:
https://github.com/NathanWalker/ng2-image-lazy-load
this work for me:
imageVarName.src = '';
imageVarName.onload = null;
imageVarName.onerror = null;
the src property must be a valid non-empty URL
So null or empty string are not legal (even though they sometimes work).
Use:
img.src='http://xxxx';
img.onerror=null;
(see here)
Sadly, setting src to an empty string does not work in WebKit-based browsers like Safari. Here is the link to the bug report which Stella mentioned.
https://bugs.webkit.org/show_bug.cgi?id=6656

Browser not updating text before inserting Ajax response with innerHTML

I'm working on a CMS which has a tree like page structure, so I am trying to emulate the Windows Explorer one uses to browser their C drive for example. So initially I list the pages at the root level, and using an onClick event and AJAX, clicking on a root page will display pages below that, in a DIV I've created/allocated for that.
All works fine, and I have an animated loading gif displayed in another DIV while xmlhttp.send is running, which is switched off when if (xmlhttp.readyState==4 && xmlhttp.status==200) is true.
The problem is that when there are a large number of sub pages (1,000 or so and yes, the client created them), the AJAX completes and the it gets to document.getElementById(DivId).innerHTML = xmlhttp.responseText; which causes the gif to stop spinning. So I've googled that and it seems this is a browser issue.
So I thought, I'll use the gif during the AJAX call and display a wait text while the browser is rendering the new innerHTML. However, despite it taking several seconds, this text never gets displayed, I just see the frozen gif and then once rendered, the "done" text.
If I comment out the "done" line, the wait text does get displayed though.
The code is below:
function getPages(page_id, DivId)
{
var loadingicon_div = "page_" + page_id + "_loadingicon";
var loading_icon = 'image here, not allowed to post images..';
document.getElementById(loadingicon_div).innerHTML = loading_icon;
xmlhttp = new GetXmlHttpObject();
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
document.getElementById(loadingicon_div).innerHTML = "Retrieved pages from the server, please wait while your browser displays them ...";
document.getElementById(DivId).innerHTML = xmlhttp.responseText;
document.getElementById(DivId).style.padding="5px";
document.getElementById(loadingicon_div).innerHTML = "done";
}
}
var url="tree_ajax.php";
xmlhttp.open("GET",url,true);
xmlhttp.send(null);
}
You should really be using a framework. I recently whipped up almost the same thing using ajax treeview built into extjs. Trust me this will save you lots of headaches. Cross browser dom is a PITA.
I know this doesn't answer your specific question, but heed my advice!
http://dev.sencha.com/deploy/dev/examples/tree/reorder.html
The only solution to this is a redesign. - no it's not, but you really should - read on ;)
The reason the animated gif stops animating is because the browser is using all it's muscle to append new elements to the DOM and to re-render/re-paint the page after this is done. There simply is no cputime left for it to animate the gif.
The slower the computer/browser is the more you will see this problem, but if you build a page with enough elements, you can make this happen in google chrome on a 4ghz computer.
The browser is a singlethreaded beast by nature when it comes to javascript/DOM manuipulation/rendering/painting and thus it can only really do one thing at a time.
It tries to make up for this by breaking complex operation up into slices and then run these slices in a way that makes it seem like it can do multiple things at once (much like operating systems does on single core machines, although much simpler)
But once you get a sufficiently complex dom structure the re-rendering/re-painting slice becomes so big that the browser seems to freeze while it happens.
As for the text not appearing:
If you wish to make a small DOM manipulation take effect (like inserting your text) before a you do a large DOM-manipulation, you need to make the browser treat this as two separate slices (which it doesn't want to do, because DOM-manipulation and subsequent re-rendering/re-painting is very cpu-costly)
To do this, break the callstack in javascript by using a setTimeout.
This will allow the browser to do a re-render/re-paint before the next DOM manipulation and subsequent re-render/re-paint.
Usually it is enough to do the setTimeout with a zero based delay, since the setTimeout in itself breaks the callstack, but in some cases you will need a small delay - play around with it and find your sweetspot :)
example:
//do small DOM manipulation here
setTimeout(function(){
//do major DOM manuipulation here
},0);

Dynamically created iframe used to download file triggers onload with firebug but not without

EDIT: as this problem is now "solved" to the point of working, I am looking to have the information on why. For the fix, see my comment below.
I have an web application which repeatedly downloads wav files dynamically (after a timeout or as instructed by the user) into an iframe in order to trigger the a default audio player to play them. The application targets only FF 2 or 3. In order to determine when the file is downloaded completely, I am hoping to use the window.onload handler for the iframe. Based on this stackoverflow.com answer I am creating a new iframe each time. As long as firebug is enabled on the browser using the application, everything works great. Without firebug, the onload never fires. The version of firebug is 1.3.1, while I've tested Firefox 2.0.0.19 and 3.0.7. Any ideas how I can get the onload from the iframe to reliably trigger when the wav file has downloaded? Or is there another way to signal the completion of the download? Here's the pertinent code:
HTML (hidden's only attribute is display:none;):
<div id="audioContainer" class="hidden">
</div>
JavaScript (could also use jQuery, but innerHTML is faster than html() from what I've read):
waitingForFile = true; // (declared at the beginning of closure)
$("#loading").removeClass("hidden");
var content = "<iframe id='audioPlayer' name='audioPlayer' src='" +
/path/to/file.wav + "' onload='notifyLoaded()'></iframe>";
document.getElementById("audioContainer").innerHTML = content;
And the content of notifyLoaded:
function notifyLoaded() {
waitingForFile = false; // (declared at beginning of the closure)
$("#loading").addClass("hidden");
}
I have also tried creating the iframe via document.createElement, but I found the same behavior. The onload triggered each time with firebug enabled and never without it.
EDIT:
Fixed the information on how the iframe is being declared and added the callback function code. No, no console.log calls here.
Old question but for future reference:
As far as my experience onLoad is not called for file downloads. A way to solve it is to use cookies like they do here http://gruffcode.com/2010/10/28/detecting-the-file-download-dialog-in-the-browser/
Here's an example that works for me, without Firebug open (tested in FF 3.6.2 Mac): http://www.jsfiddle.net/Kukry/
I'm using the jQuery .load() event instead of onload.
var iframe = $("<iframe/>").load(function () {
alert("loaded");
}).attr({
src: "http://code.jquery.com/jquery-1.4.2.min.js"
}).appendTo($("#thediv"));
Note that I'm loading a JavaScript file, not an audio file, so that might make a difference.
Maybe you call some Firebug internal function, like console.log(), somewhere? In that case, Firefox will threw an exception which can stop the execution if Firebug is not active.

Categories

Resources