Why does my image preloading method work? - javascript

My Question
The goal is to make sure all images are fully loaded before a new game can begin. My second solution (Fiddle B) achieves this goal more consistently and accurately than my first solution (Fiddle A). Why?
JSFIDDLE A
JSFIDDLE B
Methods
Here is what both of my fiddle solutions do to preload images:
There is an array of absolute image URLS for all of the assets required by the game
The init() function has a for loop which generates a new canvas Image() per URL in the array
Each newly created image is pushed into another array
So, we now have the first array containing URL strings, and a second array containing 'HTMLImageElement' objects
Fiddle B differs from Fiddle A, in that it utilises the '.onload' event, plus a counter. The two fiddles use different ways of checking to see if all the image assets have loaded:
Fiddle A: compares the length of the two arrays. If they match, start the game
for (var i = 0; i < allGameImageUrls.length; i++) {
var img = new Image();
img.src = allGameImageUrls[i];
allGameImages.push(img);
console.log(allGameImages.length);
if (allGameImages.length >= allGameImageUrls.length) {
setUpGame();
} else {
// images haven't loaded yet
console.log('STILL LOADING');
STAGE.fillText("Loading ...", 20, 400);
}
}
Fiddle B: compares the second array length with the counter variable. This counter goes up by 1 every time an image's '.onload' event completes.
for (var i = 0; i < allGameImageUrls.length; i++) {
var img = new Image();
img.onload = function () {
assetCount++;
console.log('assetCount = ' + assetCount);
setUpGame();
};
img.src = allGameImageUrls[i];
allGameImages.push(img);
}
My Question Expanded
Fiddle A frequently (but not always) triggers the start of a new game before the full list of image assets has been properly loaded, causing game errors. Fiddle B consistently loads all of the image assets before allowing a new game to start. This can be seen in both fiddles from the 'Fully loaded' messages written to the canvas.
Although I can see that Fiddle A works better than Fiddle B, I don't understand why it is superior. Not all tutorials relating to loading HTMLImageElements use '.onload', and the tutorials that don't use it seem perfectly adequate.
Additionally, I don't understand why comparing the lengths of two arrays is not as accurate as comparing the second array length to a counter.
I understand how the two solutions differ, but I want to know why solution B works better than solution A.
Previous Research
Here are just a few examples of previous research I have done in order to try to answer my own question.
An article on pre-loading images which doesn't have any reference to an .onload event
The accepted solution to this question does not use .onload event, but it still works
The accepted solution to this other question is very similar to my Fiddle B (although I discovered it much later). However, the explanation of the solution hasn't helped me to answer my own question.

You are comparing two very different approaches: sequential with for (which is incorrect) and event-based.
Image downloading is asynchronous process so when the image src property is set the browser starts downloading it. It can be, however, very fast especially if the image was already had been downloaded by the browser and cached internally (in fact, it is blazingly fast). So when the next iteration starts it is already available (or, at least, almost all of them are available at the end of the loop). But if you clear the cache or use incognito mode and download them from the remote location (not your local server) then boom! - the loop ends with no image downloaded at all.
Another approach slightly better but the game is set up for every image downloaded, which is probably do not what is required.
Consider the following approach:
var length = allGameImageUrls.length,
count = 0;
var i, img;
for (i = 0; i < length; i++) {
img = new Image();
img.onload = function () {
count++;
// count is increased on every callback
// so if number of executed callbacks equals
// the number of images then all the images
// are downloaded
if (count === length) {
setUpGame();
}
};
img.src = allGameImageUrls[i];
allGameImages.push(img);
}
The only drawback is if one of the images does not exist, the game never starts so you need to workaround it with timeout.

Related

Make GIF in Javascript from multiple images without any library

Is there any way to make GIFs in Javascript without any library? I've searched half the internet and found nothing.
Note to potential downvoters
I know that this is a low-quality question. However, I believe that the usual reasons for not answering have been invalidated. Seeing as it has been almost a month since it was asked, I doubt I'll be doing their homework as it would probably be past due for weeks at this point. And as for them not taking the time to research this myself, I'm fixing the problem at its source by teaching them how to research it.
Answer
Note that I'm answering this assuming that you know some Javascript, but not all of it, and that you want to learn how to write code that you might not yet know how to do. If you're just looking for the solution, then feel free to copy-paste it or whatever. But reading through this and understanding the process I used to tackle this problem, like how to think through it and look things up, will help you in the future. If you learn how to learn, you'll be a lot better off.
Now, first of all, we need a way to display images. I know from experience that there are two main methods to do this. One involves using the canvas element to draw the image; this is the more complicated method. Method 2 uses the image tag, <img>. I assume this is the method you want. If you didn't know how to draw an image using HTML and Javascript, a simple google search (here's another) can clear that up. (Actually, the second one mostly returns the canvas method-- but you probably knew about the image tag already anyways.)
Next we need a way to change what image is displayed. Well, that should be as simple as changing the thing that tells the image what to display in the first place. The top result from the first example search is a nice documentation page-- perfect. Reading through, I get to this part:
HTML Images Syntax
In HTML, images are defined with the tag.
The tag is empty, it contains attributes only, and does not have a closing tag.
The src attribute specifies the URL (web address) of the image:
<img src="url">
Well that looks like it's what controls what the image is. So we simply have to make a Javascript script that changes this property regularly. To do this right, we need a JS method that will wait for a specified amount of time. Searching "javascript wait" in Google, I see the second result is from the same source webpage that told me about images, so I'll go with that one. In the docs, I see this:
The setInterval() Method
The setInterval() method repeats a given function at every given time-interval.
window.setInterval(function, milliseconds);
The window.setInterval() method can be written without the window prefix.
The first parameter is the function to be executed.
The second parameter indicates the length of the time-interval between each execution.
(It even gives an example!)
This seems to be what we want. Using this method, I can make a simple code to change between two images every second (explanatory comments to the right, scroll to see them better):
function changePicture(){ //Make the function that will change the pictures
var picture = document.getElementById('picture1'); //Get the picture element from the HTML
if(picture.src == "https://vignette.wikia.nocookie.net/starpolar/images/9/96/Paul_blart.jpg/revision/latest?cb=20150419171412"){ //If it's the Paul Blart picture then:
picture.src = "https://i.ytimg.com/vi/A5KWYdrOXDk/movieposter.jpg"; //Set it to the Bee Movie
} else { //If it's not Paul Blart (and is therefore probably the Bee Movie image):
picture.src = "https://vignette.wikia.nocookie.net/starpolar/images/9/96/Paul_blart.jpg/revision/latest?cb=20150419171412"; //Set it to Paul Blart
}
}
setInterval(changePicture, 1000); //Use the new method we learned about to schedule our picture-changing function to happen once every second
<!--This is the image that we will change.-->
<img id="picture1" src="https://vignette.wikia.nocookie.net/starpolar/images/9/96/Paul_blart.jpg/revision/latest?cb=20150419171412"/>
Now, that's a good start-- we can change between 2 different totally definitely random images.
But we need more. We don't want to code in every new image manually; what we need is an array. It's hard to know that through a search, but if you've taken a primer course or learned some JS on your own you should be pretty familiar with arrays and would probably realize that they are a good option here. So we set up the array with all the images we want it to change between (scroll to the right to see it all):
var gifImages = ["https://vignette.wikia.nocookie.net/starpolar/images/9/96/Paul_blart.jpg/revision/latest?cb=20150419171412","https://i.ytimg.com/vi/A5KWYdrOXDk/movieposter.jpg","http://content.tv3.ie/content/images/0647/1_165781.jpg","https://upload.wikimedia.org/wikipedia/en/thumb/4/47/Spongebob-squarepants.svg/1200px-Spongebob-squarepants.svg.png","http://i0.kym-cdn.com/entries/icons/mobile/000/016/958/Dankkkk.jpg"];
Then we need to change our original function. It should cycle through this array of images; to do this, we'll need to make a variable to hold the position in the array.
var currentFrame = 0; //Call it a frame because we're making a gif and every image (so every array index) will be a frame
function changePicture(){
currentFrame++;
}
This should work for now, let's test it:
//Set up the array of frames
var gifImages = ["https://vignette.wikia.nocookie.net/starpolar/images/9/96/Paul_blart.jpg/revision/latest?cb=20150419171412","https://i.ytimg.com/vi/A5KWYdrOXDk/movieposter.jpg","http://content.tv3.ie/content/images/0647/1_165781.jpg","https://upload.wikimedia.org/wikipedia/en/thumb/4/47/Spongebob-squarepants.svg/1200px-Spongebob-squarepants.svg.png","http://i0.kym-cdn.com/entries/icons/mobile/000/016/958/Dankkkk.jpg"];
var currentFrame = 0; //Call it a frame because we're making a gif and every image (so every array index) will be a frame
function changePicture(){
document.getElementById("picture1").src = gifImages[currentFrame]; //Get the gif element and set its source to the current frame
currentFrame++; //Increase the current frame by 1
}
setInterval(changePicture,1000);
<!--This is the image that we will change.-->
<img id="picture1" src="https://vignette.wikia.nocookie.net/starpolar/images/9/96/Paul_blart.jpg/revision/latest?cb=20150419171412"/>
You should notice 2 things. The first is that the images have wildly different sizes and length/width ratios, resulting is the image changing size every time. The second thing you should notice is that when we run out of images, it doesn't loop back. Oops! (Side note: I actually made this mistake. Don't be discouraged by mistakes, we all make them!)
To remedy the first problem, we can look back to the HTML images documentation and see that there are two properties that can help us: width and height. These will lock the image into the specified dimensions. Frame sizes shouldn't be much of a problem with an actual gif, since the frames would probably all be the same size, but it doesn't hurt to be safe:
<img id="picture1" width="100px" height="100px" src="https://vignette.wikia.nocookie.net/starpolar/images/9/96/Paul_blart.jpg/revision/latest?cb=20150419171412"/>
The second problem is a bit harder. But looking through the code, we should be able to spot the bug fairly quickly. (Note: An experienced developer such as myself might be able to see a problem like this in a small, simple program almost instantly. Don't be discouraged if you can't; we all started somewhere and becoming a 1337 hax0r comes with time.)
If we look at how our program operates, we could say it works like this:
Loop forever:
Set the image to the current frame
Increase the frame
It becomes apparent that while we have a limited number of frames, we keep increasing the current one without going back down! Our progress through the gif would look like this (skipping to every 3rd frame and assuming 10 frames total):
|---------
---|------
------|---
---------|
---------- | <-- ???? oh no
This can be solved with a simple if statement that resets the current frame to 0 when we go past the end of our gif (line above is also shown for clarity):
currentFrame++; //Increase the current frame by 1
if(currentFrame >= gifImages.length){ //If we've gone past the end of our array of frames, then:
currentFrame = 0; //Reset back to frame 0
}
With those changes, our gif looks like this:
//Set up the array of frames
var gifImages = ["https://vignette.wikia.nocookie.net/starpolar/images/9/96/Paul_blart.jpg/revision/latest?cb=20150419171412","https://i.ytimg.com/vi/A5KWYdrOXDk/movieposter.jpg","http://content.tv3.ie/content/images/0647/1_165781.jpg","https://upload.wikimedia.org/wikipedia/en/thumb/4/47/Spongebob-squarepants.svg/1200px-Spongebob-squarepants.svg.png","http://i0.kym-cdn.com/entries/icons/mobile/000/016/958/Dankkkk.jpg"];
var currentFrame = 0; //Call it a frame because we're making a gif and every image (so every array index) will be a frame
function changePicture(){
document.getElementById("picture1").src = gifImages[currentFrame]; //Get the gif element and set its source to the current frame
currentFrame++; //Increase the current frame by 1
if(currentFrame >= gifImages.length){ //If we've gone past the end of our array of frames, then:
currentFrame = 0; //Reset back to frame 0
}
}
setInterval(changePicture,1000);
<!--This is the image that we will change.-->
<img id="picture1" width="100px" height="100px" src="https://vignette.wikia.nocookie.net/starpolar/images/9/96/Paul_blart.jpg/revision/latest?cb=20150419171412"/>
Now all we need to do is get the right frames into the array and speed it up! For a real gif, assuming this is a website you're making, the files will probably be named something like gif-frame-1, gif-frame-2, gif-frame-3, etc. Because of this, we can automate making the array, putting it into a for loop:
var gifImages = [];
for(var i=0;i<200;i++){ //Change 200 to the number of frames your gif has
gifImages[i] = "pictures/gif-frame-"+i+".png";
}
That code probably won't work with your website right away-- you have to change around the names of the images and number of frames and things-- but it should help you. If you specify where these pictures are, how they're named, how many there are, etc. then I could help you more, but I don't have enough information to write that part. Also note that this can be sped up about 50 times faster than it's going at the moment, but it looks weird without real frames to be used. For now, we can consider our final code to be:
//Set up the array of frames
var gifImages = ["https://vignette.wikia.nocookie.net/starpolar/images/9/96/Paul_blart.jpg/revision/latest?cb=20150419171412","https://i.ytimg.com/vi/A5KWYdrOXDk/movieposter.jpg","http://content.tv3.ie/content/images/0647/1_165781.jpg","https://upload.wikimedia.org/wikipedia/en/thumb/4/47/Spongebob-squarepants.svg/1200px-Spongebob-squarepants.svg.png","http://i0.kym-cdn.com/entries/icons/mobile/000/016/958/Dankkkk.jpg"];
var currentFrame = 0; //Call it a frame because we're making a gif and every image (so every array index) will be a frame
function changePicture(){
document.getElementById("picture1").src = gifImages[currentFrame]; //Get the gif element and set its source to the current frame
currentFrame++; //Increase the current frame by 1
if(currentFrame >= gifImages.length){ //If we've gone past the end of our array of frames, then:
currentFrame = 0; //Reset back to frame 0
}
}
setInterval(changePicture,100);
<!--This is the image that we will change.-->
<img id="picture1" width="100px" height="100px" src="https://vignette.wikia.nocookie.net/starpolar/images/9/96/Paul_blart.jpg/revision/latest?cb=20150419171412"/>
It's possible to touch it up (for example, you could move the function inside the setInterval itself) but this should work fine.
I hope this answer has helped you to learn how to figure these things out!
I ended up just writing a script to replace the image in a div every second. It's not technically a gif, but it works very similarly.
eval('var frame' + word + ' = 0;');
var bigFrame = 0;
setInterval(function(){ //everysecond
var noSpaces = input.replace(/\s/g, '');
var cLetter = noSpaces[bigFrame];
var thisSource = 'media/signs/alphabet/' + cLetter + '.jpeg';
$('#video').attr("src", thisSource);
$('#video').attr("alt", thisSource);
$('#video').attr("height", "350");
if(bigFrame + 1 >= noSpaces.length){
bigFrame = 0;
} else{
bigFrame = bigFrame +1;
}
for(word = 0; word < wordList.length; word ++){ //for every word
var currentFrame = eval('frame' + word);
currentWord = wordList[word];
currentWord = currentWord.toLowerCase();
console.log('current word is ' + currentWord);
var letterList = currentWord.split('');
var currentLetter = letterList[currentFrame];
var currentSource = 'media/signs/alphabet/' + currentLetter + '.jpeg';
var currentImage = "#" + eval('"image' + word + '"');
$(currentImage).attr("src", currentSource);
$(currentImage).attr("alt", currentSource);
$(currentImage).attr("height", "200");
if(currentFrame + 1 >= letterList.length){
eval('frame' + word + ' = 0');
} else{
eval('frame' + word + ' = currentFrame + 1;');
}
}
}, 1000);
I don't know if this is helpful, or even understandable, but it might help someone. Also, I haven't bothered to edit the code, so there are definitely bits that won't make sense and weird variable names.

javascript bug with canvas putImageData function inside for-loop

I was playing around with pixel-level manipulations on an HTML canvas and ran into a bug with the putImageData() function. Here's my code:
var can = document.getElementById("canvasID");
var ctx = can.getContext("2d");
var picToAlter = document.getElementById("image");
var pix = ctx.createImageData(1, 1);
var colData = pix.data;
colData[someNumber] = someValue;
ctx.drawImage("image", 0, 0);
for(let i=0;i<=can.width; i+10){
ctx.putImageData(pix, i, 0);
}
When I try to run this code in my browser (Firefox) the page simply fails to load no matter how long I wait, and, eventually, asks me if I want to stop the loading process. The problem seems to lie with my for-loop, because if I run a single instance of the code, it works. The moment I put it in a loop, though, it goes back to not loading. This is true even if I use a while-loop instead. I know that putImageData can be slow, but I feel like I'm missing something obvious that makes the loop infinite, but I just can't find it.
If you are trying to grab image data immediately (without preloading), you probably see a blank canvas. You should only run your code after preloading the image.
picToAlter.addEventListener('load', yourDrawingMethod)
Also, your for-loop is probably not behaving how you would expect. You don't want to hit can.width because it would actually be out of bounds because it's starting at zero. Also, your iteration statement isn't actually iterating. You need to use an assignment operator like i = i+10 or i+=10. Taking those issues into consideration, you would end up with something like this...
for(let i = 0; i < can.width; i+=10){
// ...
}

Sprite Animation using a for loop

I am trying to create an animation using a sprite sheet and a for loop to manipulate the background position until it has reached the total number or rows in the sheet. Ideally a reset back to the initial position would be practical, but I cannot even get the animation itself to trigger...
With the current function, no errors occur and the background position in my CSS does not change. I even recorded using Chrome DevTools Timeline and there was nothing either then everything related to my page loading. I have also tried using "background-position-y" as well as a simpler value rather then the math I currently have in place.
This is my function:
$(document).load(function() {
var $height= 324;
var $rows= 34;
for(var i=0; i<$rows; i++){
setTimeout(function() {
$('#selector').css("background-position", "0px ", "0" - ($height*i) + "px");
}, 10);
}
});
I hate to ask a question that is similar to previous issues, but I cannot seem to find another individual attempting sprite sheet animation with a for loop, so I suppose it is it's own problem.
p.s. I didn't include a snippet of my HTML and CSS because it is pretty standard and I don't see how that could be the problem. That being said, I am all ears to any potential thoughts!
I am completely revamping my answer
This issue is that the for() loop is not affected by the setTimeout so the function needs to be written on our own terms, not with a loop
Working Fiddle
Here it is..
var $height= 5;
var $rows= 25;
var i = 1; // Starting Point
(function animateMe(i){
if(i<=$rows){ // Test if var i is less than or equal to number of rows
var newHeight = 0-($height*i)+"px"; // Creat New Height Position
console.log(i); //Testing Purposes - You can Delete
$('#selector').css({"background-position": "0px "+ newHeight}); // Set New Position
i++; // Increment by 1 (For Loop Replacement)
setTimeout(function(){animateMe(i)}, 1000); // Wait 1 Second then Trigger Function
};
})(0);
Here is your solution
First Change
$(document).load() To $(document).ready()
And Change .css Syntex as
$('#selector').css("background-position",'0px '+(0 - ($height*i))+'px');
Here is fiddle Check it ihad implemented it on my recent project http://jsfiddle.net/krunalp1993/7HSFH/
Hope it helps you :)

JS performance: create an awful lot of elements at once

My web page creates a lot of DOM elements at once in a (batch) tight loop, depending on data fed by my Comet web server.
I tried several methods to create those elements. Basically it boils down to either (1):
var container = $('#selector');
for (...) container.append('<html code of the element>');
or (2):
var html = '';
for (...) html += '<html code of the element>';
$('#selector').append(html);
or (3):
var html = [];
for (...) html.push('<html code of the element>');
$('#selector').append(html.join(''));
Performance-wise, (1) is absolutely awful (3s per batch on a desktop computer, up to 5mn on a Galaxy Note fondleslab), and (2) and (3) are roughly equivalent (300ms on desktop, 1.5s on fondleslab). Those timings are for about 4000 elements, which is about 1/4 of what I expect in production and this is not acceptable since I should be handle this amount of data (15k elements) in under 1s, even on fondleslab.
The very fact that (2) and (3) have the same performance makes me think that I'm hitting the infamous "naively concatenating strings uselessly reallocates and copies lots of memory" problem (even though I'd expect join() to be smarter than that). [edit: after looking more closely into it, it happens that I was misled about that, the problem is more on the rendering side -- thanks DanC]
In C++ I'd just go with std::string::reserve() and operator += to avoid the useless reallocations, but I have no idea how to do that in Javascript.
Any idea how to improve the performance further? Or at least point me to ways to identify the bottleneck (even though I'm pretty sure it's the string concatenations). I'm certainly no Javascript guru...
Thanks for reading me.
For what it's worth, that huge number of elements is because I'm drawing a (mostly real-time) graph using DIV's. I'm well aware of Canvas but my app has to be compatible with old browsers so unfortunately it's not an option. :(
Using DOM methods, building and appending 12000 elements clocks in around 55ms on my dual-core MacBook.
document.getElementById('foo').addEventListener('click', function () {
build();
}, false);
function build() {
console.time('build');
var fragment = document.createDocumentFragment();
for ( var e = 0; e < 12000; e++ ) {
var el = document.createElement('div');
el.appendChild(document.createTextNode(e));
fragment.appendChild(el);
}
document.querySelectorAll('body')[0].appendChild(fragment);
console.timeEnd('build')
}
Fiddle
Resig on document.createDocumentFragment
This is not a solution to the performance problem, but only a way to ensure the UI loop is free to handle other requests.
You could try something like this:
var container = $('#selector');
for (...) setTimeout(function() {container.append('<html code of the element>') };
To be slightly more performant, I would actually call setTimeout after every x iterations after building up a larger string. And, not having tried this myself, I am not sure if the ordering of setTimeout calls will be preserved. If not, then you can do something more like this:
var arrayOfStrings = 'each element is a batch of 100 or so elements html';
function processNext(arr, i) {
container.append(arr[i]);
if (i < arr.length) {
setTimeout(function() { processNext(arr, i+1); });
}
}
processNext(arrayOfStrings, 0);
Not pretty, but would ensure the UI is not locked up while the DOM is manipulated.

jquery/js too slow while operating over 2000 rows

I have 2000 rows of data as follows
<div class="rr cf">
<span>VLKN DR EXP</span>
<span>01046</span>
<span>VELANKANNI</span>
<span>20:30</span>
<span>DADAR</span>
<span>10:00</span>
</div>
On a button click I am checking for text within them and updating the display of each row to block or none. The code that does this is
$('.rr').each(function(){
this.style.display="block";
});
var nodes = $(".rr");
for(var i=0;i < nodes.length; i++) {
// if data found
nodes.get(i).style.display="block";
// else
nodes.get(i).style.display="none";
}
This seems to be possibly very slow. I get chrome alert box as to kill the page.
Any ideas? what optimization can I do here?
Local Variables and Loops
Another simple way to improve the performance of a loop is to
decrement the iterator toward 0 rather than incrementing toward the
total length. Making this simple change can result in savings of up to
50% off the original execution time, depending on the complexity of
each iteration.
Taken from: http://oreilly.com/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html
Try saving the nodes.length as a local variable so that the loop doesn't have to compute it each time.
Also, you can store nodes.get(i) into a local variable to save some time if you are accessing that data a lot.
If the order isn't important, consider decrementing your for loop towards 0.
jQuery's each() loop is a bit slower than looping through the set yourself as well. You can see here that there is a clear difference.
Very simple example
You'll see that in my example, I've condensed the loop into a while loop:
var nodes = $(".rr span");
var i = nodes.length;
while(i--){
if(i%2 === 0){
nodes.get(i).style.color = "blue";}
}​
Notice that the while loop decrements i through each iteration. This way when i = 0, the loop will exit, because while(0) evaluates to false.
"Chunking" the Array
The chunk() function is designed to process an array in small chunks
(hence the name), and accepts three arguments: a “to do” list of
items, the function to process each item, and an optional context
variable for setting the value of this within the process() function.
A timer is used to delay the processing of each item (100ms in this
case, but feel free to alter for your specific use). Each time
through, the first item in the array is removed and passed to the
process() function. If there’s still items left to process, another
timer is used to repeat the process.
Have a look at Nick Zakas's chunk method defined here, if you need to run the loop in sections to reduce the chance of crashing the browser:
function chunk(array, process, context){
setTimeout(function(){
var item = array.shift();
process.call(context, item);
if (array.length > 0){
setTimeout(arguments.callee, 100);
}
}, 100);
}
Using createDocumentFragment()
Since the document fragment is in memory and not part of the main DOM
tree, appending children to it does not cause page reflow (computation
of element's position and geometry). Consequently, using document
fragments often results in better performance.
DocumentFragment are supported in all browsers, even Internet Explorer
6, so there is no reason to not use them.
Reflow is the process by which the geometry of the layout engine's
formatting objects are computed.
Since you are changing the display property of these elements iteratively, the page mush 'repaint' the window for each change. If you use createDocumentFragment and make all the changes there, then push those to the DOM, you drastically reduce the amount of repainting necessary.
Firstly, where are the delays occurring - in the jquery code, or the data check? If it is the jquery, you could try detaching the data container element (ie the html element that contains all the .rr divs) from the DOM, make your changes, and then re-attach it. This will stop the browser re-processing the DOM after each change.
I would try
1) set display of the common parent element of all those divs, to "none"
2) loop through divs, setting display as appropriate
3) set parent element display back to block
I believe this will help because it gives the browser the opportunity to aggregate the rendering updates, instead of forcing it to fully complete each single time you change the display property. The visibility of all the child node are irrelevant if the parent isnt displayed, so the browser no longer has a need to render a change in each child until the parent becomes visible again.
ALso, I fail to see the purpose of you first looping through them all and setting them all to block before you loop again and set them to their intended value.
Don't use jQuery here, jQuery will just slow things down here.
var elements = document.getElementsByClassName('rr'),
len = elements.length;
for(var i = 0; i < len; i++)
{
var ele = elements[i];
if(ele.innerHTML.search(/01046/) != -1)
ele.style.display = "none";
}
This should be much faster.
I'm also having performance problems while looping through roughly 1500 items.
As you might have guessed, the loop itself isn't the bottleneck. It's the operation you do within it that's the problem.
So, what I migrated the load using setTimeout. Not the prettiest of solutions but it makes the browser responsive between the updates.
var _timeout_ = 0;
for(var i=0;i < nodes.length; i++)
{
setTimeout(
(function(i)
{
return function()
{
if(stuff)
{
nodes.get(i).style.display="block";
}
else
{
nodes.get(i).style.display="none";
}
}
})(i),
_timeout_
);
_timeout_ += 4;
}
This will delay every update with 4 milliseconds, if the operation takes longer, the browser will become unresponsive. If the operation takes only 2 milisecond on your slowest browser, you can set it to 3, etc. just play around with it.

Categories