Why does my page leak memory from using jQuery's replaceWith? - javascript

I don't do a whole lot of JavaScript, so I'm afraid this might be a really stupid question, but I've been googling around a fair lot, and while I've found quite a bit about memory leaks with jQuery, nothing seems to match my situation.
Basically, I have a page where I'm continually replacing content with newly downloaded content. To do this, I'm using jQuery's replaceWith function, passing the downloaded HTML fragment as a string. The whole page is a bit complex and takes some time to leak significant amounts of memory, but I've reproduced the memory leak with this simple HTML snippet:
<html>
<head>
<title>Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
var sequence = 1;
function update() {
$("#test").empty().replaceWith('<p id="test">Test ' + sequence++ + '</p>').remove();
setTimeout(update, 1);
}
$(document).ready(update);
</script>
</head>
<body>
<p id="test">Test</p>
</body>
</html>
Viewing this page in Chromium seems to continually eat more and more memory, and I can't seem to figure out why. The .empty() and .remove() calls on the replaceWith() line weren't there originally, but I threw them in since they were commonly suggested as fixes to DOM replacement memory leaks. Seemingly to no effect, however.

I'm pretty sure your memory leak has something to do with the recursive nature of your setTimeout(...) function.
Try this instead:
var sequence = 1;
function update() {
$("#test").empty().replaceWith('<p id="test">Test ' + sequence++ + '</p>').remove();
var timer = setTimeout(function() {
clearTimeout(timer);
update();
}, 1);
}
$(document).ready(update);

Related

Javascript+HTA, reload iframe and keep scroll position

I created an account a very long time ago but I never really use it, as I always manage to find the answers to my questions in already solved threads. So, this is the first time since I'm working on my current program that I was not able to find a working answer on SO. However, if I simply missed it, please be nice to me ^^
A bit of context that may explain why I can't manage to apply any given solution despite many threads exists about this... I am doing:
A HTA Interface
With an iframe to a local text file
And a link to a js file that I want to use to refresh the iframe every 500 ms.
The goal is to make a chat; people can write on the text file and it automatically appears on the HTA interface.
I don't know ANYTHING about JS, frankly. So I found here that piece of code to refresh the iframe.
window.setInterval(function() {
document.getElementById('chatbox').contentWindow.location.reload();
}, 500);
It works, but upon refreshing the iframe, it scrolls back to the top; which makes the chat unreadable, as you can guess. Many solutions that I've read on SO won't work for me, maybe because it doesn't fit with this way of refreshing iframes, or with HTA, or I'm just too dumb with js to know how to make them work.
If anyone has a solution that I could just copy and use, even if I don't understand what I'm doing - it won't be very satisfying intellectually but at least I could focus on finishing my interface :) thanks a lot!
If you refresh the iframe by updating innerHTML from the text file, instead of doing a reload, it won't change the scroll position. Here's an example HTA:
<!DOCTYPE html>
<meta http-equiv="x-ua-compatible" content="ie=9">
<html>
<head>
<script>
function Refresh() {
var Iframe = document.getElementById("chatbox").contentWindow;
window.setInterval(function() {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var fh = fso.OpenTextFile(".\\Chat.txt",1);
var FileContents = fh.AtEndOfStream ? "" : fh.ReadAll();
fh.Close();
Iframe.document.body.innerHTML = "<pre>" + FileContents + "</pre>"
}, 500);
}
</script>
<style>
#chatbox {height:30em;}
</style>
</head>
<body onload="Refresh()">
<iframe id=chatbox title="Chat Box">
</iframe>
</body>
</html>

print out the highlighted text which follows, a single character at a time with a 10-millisecond delay between each character being displayed

when I click the button it will not run
Add a button with id btnPrint and value “Print” and an event handler called printString()
add a which will be used to receive (and display) the characters in the string incrementally. This would look something like:
document.getElementById("outDiv").innerHTML += myNextChar;
Display 100 characters on a line and then start a new line, continuing until all the characters have been displayed.
<html>
<head>
<title>Exercise</title>
<script language="JavaScript" type="text/JavaScript">
function printString(){
str="The nefarious thing about performance bugs is that the user may never know they are there - the program appears to work correctly, carrying out the correct operations, showing the right thing on the screen or printing the right text. It just does it a bit more slowly than it should have. It takes an experienced programmer, with a reasonably accurate mental model of the problem and the correct solution, to know how fast the operation should have been performed, and hence if the program is running slower than it should be";
var myNextChar="";
var char=0;
function innerLoop(){
myNextChar=str.slice(char,char+1);
if((char+1)%100===0){
myNextChar+="<br />"
}
char++;
document.getElementById("str").innerHTML += myNextChar;
setTimeout(innerLoop,10);
}
innerLoop();
}
//window.onload = printString;
</script>
</head>
<body>
<button onclick="printString()">Print</button>
</body>
Uncaught TypeError: Cannot read property 'innerHTML' of null
at innerLoop (Exercise4.html:16)
at printString (Exercise4.html:20)
at HTMLButtonElement.onclick (Exercise4.html:28)
You need move your script to before close </body> tag and add a div with id str
<div id='str'></div>
function printString(){
str="The nefarious thing about performance bugs is that the user may never know they are there - the program appears to work correctly, carrying out the correct operations, showing the right thing on the screen or printing the right text. It just does it a bit more slowly than it should have. It takes an experienced programmer, with a reasonably accurate mental model of the problem and the correct solution, to know how fast the operation should have been performed, and hence if the program is running slower than it should be";
var myNextChar="";
var char=0;
function innerLoop(){
myNextChar=str.slice(char,char+1);
if((char+1)%100===0){
myNextChar+="<br />"
}
char++;
document.getElementById("str").innerHTML += myNextChar;
var id = setTimeout(innerLoop,10);
if(char > str.length) clearTimeout(id);
}
innerLoop();
}
//window.onload = printString;
<html>
<head>
<title>Exercise</title>
</head>
<body>
<button onclick="printString()">Print</button>
<div id='str'></div>
</body>

IE9 triggers img element onerror event when too many images

Problem
The problem is that <img> onerror is trigerring in IE9 when there are already too many images on the page even though images are properly loaded. Too many images is actually around 100 - 200 images of around 1600 x 2300. I can't post a fiddle since I don't have 200 URLs for images like this so anyone interested, I have a favor to ask and replicate on you local machine.
Testing this issue might be a little tedious so please bear with me sirs. I will give a little bounty for this because of it's hassle haha.
Prerequisites (EDIT: see fiddle instead)
Any image preferably around 1600 by 2300 (mine is about 800KB) and IE9 (didn't test any other IE yet sorry, maybe you can try)
Name that image 1.jpg and save in any empty folder
Copy and paste that image 200 times (100 may do it, but to be safe) on the same folder.
By now you should get file names like 1 - Copy (x).jpg, where x is 0 - 200.
In the same folder, make an html file with the code below.
Code
<html>
<head>
<title>Test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" type="text/javascript"></script>
<script>
$(document).ready(function() {
var i = 0;
$("#btn").click(function() {
var str = "";
var limit = i + 20;
$("div.toBeHidden").hide();
str += "<div class='toBeHidden'>"
for( ; i < limit && i < 200 ; i++) {
str += "<img src='1 - Copy (" + i + ").jpg' alt='Not found' onerror='console.log(\"too bad\");' height='50' width='50'/>";
}
str += "</div><br/>"
$("#container").append(str);
});
});
</script>
</head>
<body>
<input type="button" id="btn" value="Test"/>
<div id="container">
</div>
</body>
</html>
If you are able to replicate it, you should there should be prints "Too bad" in your console the 3rd or 4th time you press the "Test" button. What's worse is that after the first "Too bad" anything after is triggering onerror.
The loop in your code snippet shows 200 iterations, not 20, so on the 3rd or 4th click, you have added between 500-600 images.
I suspect that IE9 has a limit (maybe 2^9 = 512?) on resources it allows at once.
I'd suggest removing old images from the DOM once they have been scrolled out of view. The user will only see a few images at once, so you can optimize your page to be more memory efficient (mobile users will be grateful).
sir why dont u disable onerror
this.onerror=null;
As an option you may try to modify the src attribute values of <img> elements instead of replacing whole DOM fragment to solve memory issues.
For the infinite scroll you can also reuse these fragments, just need to have several of them in memory and switch when needed.

javascript mouse event compatibility issue between browsers

I am new to the web development. I have a code that's supposed to change images when clicked on the image, and change the image back when released. And also it counts how many times it is clicked. I was building and testing this code on Safari and I didn't had any problems. It works just as expected on Safari. However it does not work on Chrome and IE (I haven't tested any other browsers).
I was normally working with HTML5 Boilerplate however I reduced the code so that I can show here (This version doesn't work too).
I have given the code of the page below. What should I do to make it work on every browser. What is the reason that it acts differently on browsers?
Thanks in advance
<!html>
<html>
<head>
<title></title>
<script type="text/javascript">
var count = 0;
function incrementCount()
{
count++;
document.getElementById( "count").innerHTML = count;
}
function pushTheButton()
{
document.images("bigRedButton").src = "img/pressed.gif";
return true;
}
function releaseTheButton()
{
document.images("bigRedButton").src = "img/unpressed.gif";
return true;
}
</script>
</head>
<body>
<div role="main">
<p>
<img src = "img/unpressed.gif" name="bigRedButton" onmousedown="pushTheButton()" onmouseup="releaseTheButton()" onclick="incrementCount()"/>
</br>
Click Count:<p id="count">0</p>
</p>
</div>
</body>
</html>
When testing in Chrome, remember to use its JavaScript console to watch for errors. In this case, it returns the following:
Uncaught TypeError: Property 'images' of object # is not a function
Your problem is on lines 18 and 24, when you attempt to access document.images("bigRedButton") -- document.images is an array (or possibly an object), not a function. It should be:
document.images["bigRedButton"].src
I don't know why it worked on Safari.
http://www.w3schools.com/jsref/coll_doc_images.asp
document.images is documented a integer-indexed array of images.
To be really sure, you should use:
document.images[0].src = ...
Although accessing the image by using the name works in many cases as well.

Possible to flash a Browser window using Javascript?

Like many programs flash their window on the taskbar / dock to alert the user to switch to the program,
Is it possible to flash the Browser window using Javascript? (FireFox-only scripts are also welcome)
This is useful for web-based Chat / Forum / Community-based software where there is lots of real-time activity.
#Hexagon Theory: Why would you ever rewrite the whole head element just to change the value of one element in the head? Your solution is horribly inefficient on multiple levels.
<html>
<head>
<link rel="icon" href="on.png" type="image/png" id="changeMe" />
<script type="text/javascript" src="flash.js"></script>
</head>
<body>
</body>
</html>
flash.js:
function Flasher(speed) {
var elem = document.getElementById('changeMe');
this.timer = setTimeout(function() {
elem.href = elem.href == 'on.png' ? 'off.png' : 'on.png';
}, speed);
this.stop = function() { clearTimeout(this.timer); }
}
/* sample usage
*
* var flasher = new Flasher(1000);
* flasher.stop();
*/
It didn't really have to be a class but it helped keep the global namespace clean. That's untested but if simply changing the href doesn't work for some reason, clone the link node, change the href and replace the old link with the cloned one.
At this point, it seems only causing an alert dialog to pop up does the trick... this seems a bit too intrusive, I feel, particularly given the use you're trying to put it to. Instead of causing it to flash, though, you could modify document.title to grab the user's attention, either by prepending some signal (perhaps the string "NEW!") to the site's name, and then using an interval to constantly change it to "", which would then give a nice little "flashing" illusion.
Bare-bones example:
<html>
<head>
<title>Chat System</title>
<script>
var timer, old_t = document.title, blink_amount = 5, cur_b = 0;
function notify()
{
cur_b = 0;
timer = setInterval(function()
{
if (cur_b < blink_amount * 2)
{
cur_b++;
document.title = (document.title.indexOf('NEW! ') != -1) ? old_t : 'NEW! ' + old_t;
}
else
{
clearInterval(timer);
}
}, 600);
}
notify();
// From here, it's just a matter of calling the
// notify() function whenever you detect a new message.
</script>
</head>
<body>
</body>
</html>
Hey, another interesting solution to this question hit me just now. Why not really grab the user's attention by making the icon flash in their browser? You could, for example, make two icons (on.png and off.png in my example below) and repeatedly swap them out to really catch a user's eye. The following is a bare-bones implementation; do keep in mind that you will need to reference this script remotely or put it in the body of the page because it uses a method that repeatedly replaces the content of the <head> tag. Give it a try, though; I rather like the simplicity of it.
page.html:
<html>
<head>
<link rel="icon" href="on.png" type="image/png" />
<script type="text/javascript" src="flash.js"></script>
</head>
<body>
</body>
</html>
flash.js:
var timer, speed = 175;
function flash()
{
head_html = document.getElementsByTagName('head')[0].innerHTML;
if (head_html.indexOf('href="on.png"') != -1)
document.getElementsByTagName('head')[0].innerHTML = head_html.replace('on.png', 'off.png');
else
document.getElementsByTagName('head')[0].innerHTML = head_html.replace('off.png', 'on.png');
timer = setTimeout('flash()', speed);
}
function kill_flash() {clearTimeout(timer);}
flash();
Mozilla previously had Window.getAttention() but by 2018 no browsers were listed supporting it. https://web.archive.org/https://developer.mozilla.org/en-US/docs/Web/API/Window/getAttention
Its behavior:
Windows, the taskbar button for the window flashes
Linux, some window managers flash the taskbar button, others focus the window immediately
Macintosh, the icon in the upper right corner of the desktop flashes
Window.Focus() should do it on Windows, not sure on other platforms though. You might find it brings the Window to the foreground if it's minimised though, which would be very annoying :)

Categories

Resources