Read and replace text in HTML causes high CPU load - javascript

I have a problem with high CPU load on a website where I want to replace some text with links.
The script is loaded at the end of body.
This works normally when there are no videos on the page. But if there are videos embedded like this the CPU load goes above 50%. If I use this for multiple files Firefox crashes.
<p><video width="320" height="240" class="mediaelement" autoplay="autoplay" src="video.mp4" controls="controls">resources/video.mp4</video></p>
I figured out the problem is in this, especially the readout from csv. If I just replace the text with fixed data it works as well.
var rawFile = new XMLHttpRequest();
rawFile.open("GET", "data.csv", false);
rawFile.overrideMimeType('text/xml; charset=iso-8859-1');
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
{
if(rawFile.status === 200 || rawFile.status == 0)
{
var allText = rawFile.responseText;
allText = allText.split("\n");
var sizedata = Object.size(allText); //Number of entries
var sizedata = sizedata -1; //Excel +1
//alert("Debug: " + sizedata);
var i = 0;
while (i < sizedata)
{
var word = allText[i].split(";");
var wordToDefine = word[0];
var wordDefinition = word[1];
var wordToReplace = wordToDefine
var replaceItem = new RegExp(wordToReplace,"g");
document.body.innerHTML = document.body.innerHTML.replace(replaceItem, " <a href='data.html' target='_self'><span style='color:green' title='WORD'>WORD</span></a>");
i = i+1;
}
}
}
}
rawFile.send(null);
Any ideas what I can do about this?
Thank you in advance.

As #criz already mentioned, building DOM in a loop is a very bad practice. It's much better to create documentFragment and attach it to the DOM. Take a look at the https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment There is an example.

Related

I'm having a bit of trouble with the Javascript Onclick event when trying to toggle between images

So for one of my labs, I'm trying to get a blurred image with one src to appear as a clear image from a different source. So far I've only managed to change the blurred image to the clear image, but not the other way around.
So far, I have the if statement and a string indexOf as a part of my lab requirements. Now bear in mind that by my instructions, I'm not allowed to edit any HTML for this project.
function toggleImages(){
//(document.getElementById("clickimage").src = 'images/lab9_blurred');
//console.log(str.indexOf("clickimage"));
//var images = 'images/lab9_blurred.jpg';
var str = "images/lab9_blurred.jpg";
console.log(str.indexOf("blurred"));
var str = "images/lab9_clear.jpg";
console.log(str.indexOf("clear"))
//click it once, it's true, click it again, it's false. That's what should happen. But how do we do that?
//If image = "images/lab9_blurred.jpg" then for variable image we get clickimage, set variable name to lab 9 clear, and set image source to name.
//if (fake == true){
if (str.indexOf("blurred") == 12){
var image = document.getElementById("clickimage");
var name = "images/lab9_blurred.jpg";
image.src = name;
console.log(str.indexOf("blurred"));
}
else if (str.indexOf("clear") == 12)
{
var image = document.getElementById("clickimage");
var name = "images/lab9_clear.jpg";
image.src = name;
console.log(str.indexOf("clear"));
}
};
window.onload = init;
Hi try following code...
function toggleImages(){
var image = document.getElementById("clickimage");
if (image.src.indexOf("blurred") == 12)
{
var str = "images/lab9_clear.jpg";
console.log(str.indexOf("clear"))
}
else
{
var str = "images/lab9_blurred.jpg";
console.log(str.indexOf("blurred"));
}
image.src = str;
};
window.onload = init;

DOM Update slow in chrome than firefox looks like chrome has some rendering issues

I have written a code which dumps large no of node in DOM . When i load it in firefox it renders in 2-3 secs but in chrome (ver:33) it freezes the UI and rendering takes long time(8-10 sec) .
$.ajax({
xhr: function () {
var xhr = new window.XMLHttpRequest();
xhr.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total * 100;
$("#fetchProgress").attr("value", percentComplete);
}
}, false);
return xhr;
},
type: 'GET',
url: "/GetSomething",
data: {},
success: function (data) {
///process and dump to DOM//
var fileLines = data.split('\n');
var htmlString = '';
for (var i = 0; i < fileLines.length; i++) {
htmlString += '<span>' + (i + 1) + '. ' + fileLines[i]+</span>;
if ((i % 1000) == 0) {
$("#textPlace").append(htmlString);
htmlString = '';
}
}
fileLines = null;
$("#textPlace").append(htmlString);
}
});
I learned from internet that chrome has some rendering bugs and tried hacks from this URL.
"Chrome Bug - window.scroll method intercepts DOM Rendering"
It started to work but now again it is not working .Please suggest something .
Any help is appreciated . Tank size Thanks in Advance :)
If I understand your code, you have an array which you want to tie together with spans. You can remove the for() from your code (and the modulus in it(=slow) ), saving a lot of time:
htmlString = '<span>'+ fileLines.join("</span><span>") +'</span>';
That will not display the i number, but you could switch to li's and use the numbers instead of bullets.
This might work too:
var fileLines = '<span>'+ data.replace('\n', '</span><span>') +'</span>';
This is a litte more messy (this could end in </span><span></span>, you need to trim \n's to fix that (easy to do)), but it doesnt have to turn it into an array, which should speed things up
See if you can avoid the append to html under this function
if ((i % 1000) == 0) {
$("#textPlace").append(htmlString);
htmlString = '';
}
and only have one append at the very end of your code. You want to limit the DOM manipulation - it affects the browser performance by triggering multiple browser reflow.
Google Dev: Speeding up JavaScript: Working with the DOM
Taken out from the link above, you can work with something like this instead
var anchor, fragment = document.createDocumentFragment();
for (var i = 0; i < 10; i ++) {
anchor = document.createElement('a');
anchor.innerHTML = 'test';
fragment.appendChild(anchor);
}
element.appendChild(fragment);

document.write causes strange behavior with Google Chrome

[Problem]
Disappearing other JS contents(facebook Like button) on same page with following JS.
(Only Google Chrome)
This bug is caused by following JS.
[Question]
Why the bug happened?
And this solution is right?
If you have any idea, could you tell me?
I tried to make "text" has document.write() part without document.open() and document.close().
But, it didn't cause disappearing other JS contents.
[Target Code]
This javascript is executed in iframe.
Then, the iframes will be output in iframe.
View.prototype.make_iframe = function(id, text) {
var doc, iframe, isIE;
iframe = document.createElement("iframe");
iframe.width = 0;
iframe.height = 0;
iframe.id = id;
document.body.appendChild(iframe);
doc = iframe.contentWindow.document;
/* Problem part start */
doc.write("<html><head></head><body>");
doc.write(text);
doc.write("</body></html>");
/* Problem part end */
};
View.prototype.get_tag_files = function(dir, fname, data, make_iframe) {
var xmlObj;
xmlObj = null;
if (window.ActiveXObject) {
xmlObj = new ActiveXObject("Msxml2.XMLHTTP");
} else {
xmlObj = new XMLHttpRequest();
}
xmlObj.onreadystatechange = function() {
var i, item, tag, text, _i, _len;
if (xmlObj.readyState === 4 && xmlObj.status === 200) {
text = xmlObj.responseText;
tag = new Tag(data, text);
tag.replace();
return make_iframe(fname, tag.get_tag());
}
};
xmlObj.open("GET", dir + fname, true);
return xmlObj.send(null);
};
[Solution]
/* target part */
doc.write("<html><head></head><body>");
doc.write(text);
doc.write("</body></html>");
==>
/* replaced target part */
isIE = /MSIE/.test(window.navigator.userAgent);
if (!isIE) {
doc.clear();
doc.open;
}
doc.write("<html><head></head><body>");
doc.write(text);
doc.write("</body></html>");
if (!isIE) {
return doc.close();
} else {
return;
}
To : First commenter
Thank you for your response.
I tried to use appendChild function.
But, it doesn't work.
"text" variable has some HTML and JS tags which get data from other servers.
When I used appendChild instead of document.write function,
the tags can't communicate other server via network.
I don't know the cause.
This code is generated by coffee script compiler.
And coffee script code has the view class, so the code has prototype.
Original code(coffee script) is following one.
Tag = require("../src/tag").Tag
class View
constructor: (data) ->
#validated = data
#viewid = "product"
make_iframe: (id,text) ->
iframe = document.createElement("iframe")
iframe.width = 0
iframe.height = 0
iframe.id = id
document.body.appendChild(iframe)
doc = iframe.contentWindow.document
isIE = /MSIE/.test(window.navigator.userAgent)
if !isIE
doc.clear()
doc.open
doc.write("<html><head></head><body>")
doc.write(text)
doc.write("</body></html>")
if !isIE
return doc.close()
else
return
get_tag_files: (dir,fname,data,make_iframe) ->
xmlObj = null
if window.ActiveXObject
xmlObj = new ActiveXObject("Msxml2.XMLHTTP")
else
xmlObj = new XMLHttpRequest()
xmlObj.onreadystatechange = ->
if xmlObj.readyState == 4 && xmlObj.status == 200
text = xmlObj.responseText
tag = new Tag(data, text)
tag.replace()
make_iframe(fname,tag.get_tag())
xmlObj.open("GET", dir+fname, true)
xmlObj.send(null)
output_tags: (tags, path) ->
for tag in tags
#get_tag_files(path, tag, #validated, #make_iframe)
return """
"""
exports.View = View

Preloading images in an array (and waiting until they have downloaded)

So I came across another problem.
When I started redoing the webpage I am working on , I came across an idea - Why not have the page preload the materials, and while it's doing just that, show a loading screen?
Well, I made a function for that, but the thing is, it starts doing what it's supposed to, until it comes to the open() part of the image preloading. It simply does not work. It is because I am giving it the arguments[i] part that is causing it to stop there? Is there a better way to do it?
function mainPageLoad() {
var loadScreen = document.getElementById('pageload');
loadScreen.innerHTML = "<p>Loading<span id='loadingWhat'>...</span></p><img src='images/loading.gif?v2'>";
var loadspan = document.getElementById('loadingWhat');
loadspan.innerHTML = " images";
preloadImages(["images/logo.jpg"])
//loadspan.innerHTML = " content";
//preloadContent([""]);
}
function preloadImages() {
var images = new Array();
var imagesToLoad = arguments.length;
document.writeln(imagesToLoad);
var imagesLoaded = 0;
document.writeln(imagesLoaded);
for (i = 0; i < arguments.length; i++) {
document.writeln("Loading images.");
images[i] = new XMLHttpRequest();
document.writeln("Made object");
images[i].open("GET", arguments[i], true);
document.writeln("Well, that worked.");
images[i].send(null);
document.writeln("Sent.");
images[i].onreadystatechange = function() {
document.writeln("Ready state change!");
if (images[i].readystate == 4 && images[i].status == 200){
imagesLoaded = imagesLoaded + 1;
window.alertln("We have loaded another image.");
window.alertln("Image" + String(imagesLoaded) + "out of" + String(imagesToLoad));
}
}
}
}
window.onload = init;
Here's a much, much simpler way to preload images and have it call a callback when the images are done loading in a related prior question/answer: Image preloader javascript that supports events.

load remote images via Javascript, then selectively add to array

Using javascript I'm trying to load images not on the current page (from an array of image links) and if they are large enough, add them to an array. I'm executing this after the current page has loaded, though a bookmarklet, or firebug console. Using FF.
The closest I've come is the below, but this does not seem to work, and I'm guessing this is because the size test is running before the images have loaded. Apparently my attempt to fix this with 'onload' does not work. How can I fix this up, or is there a better/simpler way to accomplish this task?
(function() {
//create array for the images
var imageArray = new Array();
function loadIfBig(x){
if (x.height > 299 && x.width > 299 && (x.height > 399 || x.width > 399)) {
imageArray.push(x);
//dispImage = '<img src=' + x.src + '><br>';
//document.write('<center>' + dispImage + '</center>');
}
return true;
}
//given an array of imageLinks:
for (x in imageLinks){
//create an image form link and add to array if big enough
im = document.createElement('img');
im.src = imageLinks[x];
im.onload = loadIfBig(im);
}
//view results:
for (x in imageArray){
disp_image = '<img src='+imageArray[x].src+'><br>';
document.write('<center>'+disp_image+'</center>');
}
})();
Update:
Thanks! sure you're right and I'm missing something stupid here, but I made the change you suggested, and then pulled writing the elements into loadIfBig, but it doesn't seem to be executing that function. current code below, including a couple sample input links:
(function() {
var imageArray = new Array();
var imageLinks = ['http://1.bp.blogspot.com/_mfMRTBDpgkM/SwCwu1RPphI/AAAAAAAAJpw/v9YInFBW84I/s1600/800px-San_Francisco_in_ruin_edit2.jpg','http://2.bp.blogspot.com/_mfMRTBDpgkM/SwCwulSZ_yI/AAAAAAAAJpo/NsRcJdpz4Dk/s1600/San_Francisco_PC_59.jpg']
function loadIfBig(x){
if (x.height > 299 && x.width > 299 && (x.height > 399 || x.width > 399)) {
imageArray.push(x);
dispImage = '<img src=' + x.src + '><br>';
document.write('<center>' + dispImage + '</center>');
}
return true;
}
processImages = function(){
for (x in imageLinks) {
//create an image from link and add to array if big enough
im = document.createElement('img');
im.src = imageLinks[x];
im.onload = function(){
loadIfBig(this);
}
}
}
})();
Your fix doesn't work because you're actually executing it immediately.
im.onload = loadIfBig(im) is actually running the function.
What you can do is something like:
im.onload = function() {
loadIfBig(this);
}
Another problem is the fact that you're running through the array of big images before the onload callbacks have actually executed. That needs to be stuck in a different function and called once all the onloads are done.

Categories