I have created a node-webkit application that loads thousands of images (7,480 to be exact) from disk into an HTML table. After about 3500 images, the loading stops. In the console, I see ERR_INSUFFICIENT_RESOURCES. According to Task Manager, the memory (private working set) for my app is at around 1.37 GB when this happens. How can I prevent this from happening? Is there a way for me to increase this limit? What additional details should I provide to receive help?
In the past when i have faced a similar problem, i held the images in memory, and inserted them into the dom as they scrolled into view.
I created two queues one for images not the scroll down to, and one for images that have been scrolled past. this way only images that are visible are present in the page.
If the download time is an issue try loading them into memory and see what happens, there is a chance the limit you have encountered is about placing images in the dom, and not necessarily loading the images into memory, worth a try.
https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image
var myImage = new Image(100, 200);
myImage.src = 'picture.jpg';
Related
I may be off the mark here but I wanted to find out if there actually is a solution to this problem before I try and solve it.
I'm using cordova on iOS and accessing the device's image gallery, fetching a photo's file.uri (the least memory hungry way according to phongap docs) and then rendering this into a roughly 50px x 50px image on the page.
The problem I've run into is that once I have loaded 4 or more photos onto the page, the performance starts to suffer, focus on other form elements becomes slow, and somewhat 'jerky'. I believe that this has to do with the fact that I am obviously rendering a high resolution image in a tiny box and when you have multiple high res images on one page you put a serious strain on the device's resources. This is on an iPhone 5, I would imagine the performance to be worse still on a 4s and 4.
Is there a way to programatically create 'low res' versions of the image(s) and then use these low res images on my page? In theory I have access to the image and its location, so can I not convert/compress/downscale these on the fly for the purpose of improving performance and then ditch these thumbnails/temp images once any upload of the actual image files is complete?
You could use a html canvas to create low res images.
Beter try this.
Take that image url in a string.
NSString *imgUrl=YourImageURL;
To get low resolution images you can divide the occurences of 1024x768 with 200x200.
NSString *strURLLowRes = [imgUrl stringByReplacingOccurrencesOfString:#"1024x768" withString:#"200x200"];
Now you can load the low resolution image.
Hope this helps you.
I played around with a bunch of images that with that are loaded from within a javascript like so:
albumArray[16][214] = new Image();
albumArray[16][214].src = 'dalb214.png';
I am replacing these with bigger sprite images to keep the http requests down, but one thing I noticed when I was playing around was that the connection time for the images loaded in javascript was much longer than that of images loaded with html in chrome dev tools.
normal image connection time: 1-3ms
javascript images: 300-350ms
this seems very strange to me to the point where I am wondering if I am doing anything wrong.
What is causing the long connection time for my javascript images and what can I do to speed it up?
The heading sums is all. Though, the case is where I have a long (20x2000px) picture as a sprite for thumbnails. It would be nice if I could start showing the sprite only for the thumbnails that already have required-part of the sprite loaded, and show loader in the meantime.
All I need is to know how much of the picture has been loaded in pixels from the top (supposing that it is not progressive). I thought of using file size to estimate that, though that would be very inaccurate.
The main question everyone is having - why to do this at all?
There is a page that displays somewhat 100 thumbnails. It would be a nice thing if this page had a sprite of those thumbnails generated in the descending thumbnail order.
Such page already exists. The screenshot is attached. User can see a gray placeholder while the sprite is being loaded. I want to display the thumbnail only when the required part of the sprite for that thumbnail is already loaded.
#Guy Sounds like a theoretical question then... Per your comment on the answer below, if you're loading 10MB 'sprites' you're doing it wrong.
No, there is nothing wrong about it if this can be achieved. That would reduce the number of calls by 100 every time the page is being called. That is a remarkable speed improvement even if everything is cached.
I see what you're trying to do, but in short, you can't. Counting pixels in JavaScript, if it possible at all (maybe with canvas? I don't think so though) would just be unreasonably resource-consuming. Loading all the images separately (i.e., not as one sprite), however, will give you exactly the effect you're looking for as a default on most browsers, albeit at the cost of more requests.
The solution? Use a Content Delivery Network (CDN), so the browser can fetch all 100 images at the same time, without necessarily putting the strain on your own server.
EDIT:
After some additional searching, I found what looks to be a solution here and is similar to a solution provided here. The basic idea is to make an AJAX request and monitor the progress.
If I'm understanding you correctly, you want to avoid that brief period of time that a page is loading (or after a even occurs) where images haven't finished transferring and don't yet appear where they should.
The problem I think you're going to run into (if this is a scenario where the page is loading) is that you're waiting for your placeholder image and the sprite to come across the wire. By the time your placeholder gets over, your sprite may have gotten there already or be milliseconds behind, and you haven't avoided the situation described above.
If you're dealing with a mouseover event or something similar where the sprite is requested for the first time, you can pre-load the sprite image by calling it via JavaScript when the page loads, so it'll already be cached and ready when the event fires.
I already have a theoretical solution. Before I start working on it, it would be nice if anyone can tell me if there is any major fault in my thinking.
The image is generated server-side, screenshot after screenshot. Therefore, after every screenshot merged into the sprite I can save the thumbnail size information to the database along with the corresponding entry.
Once user lands on the page, I will keep checking how many bytes of the sprite are loaded, loop through every entry that is pending to be displayed, check if the value is greater or equal to the entry "weight" and display or continue the loop appropriately.
Does anyone know why Javascript performance would be affected by the loading of lots of external JPG/PNG images into HTML5 Image() objects, totalling approx 200Mb-250Mb. Performance also seems to be affected by cache. Ie. if the cache is full(-ish) from previous browsing the performance on the current site is greatly reduced.
There are 2 says i can crudely solve it.
clear cache manually.
minimise browser, wait about 20 secs and re-open the browser after which time the iOS/browser has reclaimed the memory and runs the JS as it should.
I would have expected the iOS to reclaim required memory to run the current task, but it seems not. Another workaround is to load 200Mb of 'cache clearing' images into Image() objects, then remove these by setting the src = "". This does seem to help, but its not an elegant solution...
please help?
First and foremost read the excellent post on LinkedIn Engineering blog. Read it carefully and check if there are some optimizations that you can also try in your application. If you tried all of them and that still haven't solved your performance issues read on.
I assume that you have some image gallery or magazine-style content area on your page
How about having this image area in a separate iframe? What you could do then is this:
Have two iframes. Only one should be visible and active in time.
Load images into first iframe. Track the size of loaded images. If exact size tracking is hard
numberOfLoadedImages * averageImageSize
might be a pretty good aproximation.
As that number approaches some thresshold start preloading the currently visible content into second iframe.
Flip the visibility of iframes so the second one becomes active.
Clear the inner content of the first frame.
Repeat the whole procedure as necessary.
I don't know for sure if this would work for you but I hope that WebKit engine on iPad clears the memory of frames independently.
EDIT: It turned out you're writing a game.
If it's a game I assume that you want to have many game objects on the screen at the same time and you won't be able to simply unload some parts of them. Here are some suggestions for that case:
Don't use DOM for games: it's too memory-heavy. Fortunately, you're using canvas already.
Sprite your images. Image sprites not only help reducing the number of requests. They also let you reduce the number of Image objects and keep the per-file overhead lower. Read about using sprites for canvas animations on IE blog.
Optimize your images. There are several file size optimizers for images. SmushIt is one of them. Try it for your images. Pay attention to other techniques discussed in this great series by Stoyan Stefanov at YUI blog.
Try vector graphics. SVG is awesome and canvg can draw it on top of canvas.
Try simplifying your game world. Maybe some background objects don't need to be that detailed. Or maybe you can get away with fewer sprites for them. Or you can use image filters and masks for different objects of the same group. Like Dave Newton said iPad is a very constrained device and chances are you can get away with a relatively low-quality sprites.
These were all suggestions related to reduction of data you have to load. Some other suggestions that might work for you.
Preload images that you will need and unload images that you no longer need. If your game has "levels" or "missions" load sprites needed only for current one.
Try loading "popular" images first and download the remaining once in background. You can use separate <iframe> for that so your main game loop won't be interrupted by downloads. You can also use cross-frame messaging in order to coordinate your downloader frame.
You can store the very most popular images in localStorage, Application Cache and WebSQL. They can provide you with 5 mb of storage each. That's 15 megs of persistent cache for you. Note that you can use typed arrays for localStorage and WebSQL. Also keep in mind that Application Cache is quite hard to work with.
Try to package your game as a PhoneGap application. This way you can save your users from downloading a huge amount of data before playing the game. 200 megs as a single download just to open a page is way too much. Most people won't even bother to wait for that.
Other than that your initial suggestion to override cache with your images is actually valid. Just don't do it straight away. Explore the possibilities to reduce the download size for your game instead.
I managed to reduce the impact by setting all the images that aren't currently in the viewport to display:none. This was with background images though and I haven't tested over 100Mb of images, so can't say whether this truly helps. But definitely worth of trying.
I need to dynamically load and put on screen huge number of images — it can be something like 1000–3000. Usually these pictures are of different size, and I'm getting their URLs from user. So, some of these pictures can be 1024x800 or 10x40 pixels.
I wrote a good JS script showing them nicely on one page (ala Google Images Search style), but they are still very heavy on RAM used (a hundred 500K images on one page is not good), so I thought about the option of really resizing images. Like making an image that’s 1000x800 pixels something like 100x80, and then forget (free the ram) of the original one.
Can this be done using JavaScript (without server side processing)?
I would suggest a different approach: Use pagination.
Display, say, 15 images. Then the user click on 'next page' and the next page is shown.
Or, even better, you can script that when the user reaches the end of the page the next page is automatically loaded.
If such thing is not what you want to do. Maybe you want to do a collage of images, then maybe you can check CSS3 transforms. I think they should be fast.
What you want to do is to take some pressure from the client so that it can handle all the images. Letting it resize all the images (JavaScript is client side) will do exactly the opposite because actually resizing an image is usually way more expensive than just displaying it (and not possible with browser JS anyway).
Usually there is always a better solution than displaying that many items at once. One would be dynamic loading e.g. when a user scrolls down the page (like the new Facebook profiles do) or using pagination. I can't imagine that all 1k - 3k images will be visible all at once.
There is no native JS way of doing this. You may be able to hack something using Flash but you really should resize the images on the server because:
You will save on bandwidth transferring those large 500K images to the client.
The client will be able to cache those images.
You'll get a faster loading page.
You'll be able to fit a lot more thumbnail images in memory and therefore will require less pagination.
more...
I'm (pretty) sure it can be done in browsers that support canvas. If this is a path you would like to take you should start here.
I see to possible problems with the canvas approach:
It will probably take a really long time (relatively speaking) to resize many images. Because of this, you're probably going to have to look into utilizing webworkers.
Will the browser actually free up any memory if you remove the image from the DOM and/or delete/null all references to those images? I don't know.
And some pretty pictures of a canvas-resized image:
this answer needs a ninja:--> Qk