Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

net::ERR_INSUFFICIENT_RESOURCES error when adding numerous img elements to dom

I'm using jquery and backbone.js on a site that is pretty image heavy. The core functionality of the site involves many many fairly small images (150x180px jpg files). The list of images comes in via ajax/json using a backbone.js collection fetch. Then for each model in the collection there is a view that gets rendered which contains an img element. The view is then added to the dom.

There is one user in particular that has thousands of images - a super edge-case relative to how many images most of our normal users have. When this user's image data loads, the browser just can't handle loading all the images, at least in the way our current code works. About half of the images load okay eventually, but the browser (i'm using chrome 35) becomes unresponsive for several minutes. The other half of the images fail to load, and the browser console shows "net::ERR_INSUFFICIENT_RESOURCES" errors for the images that don't load.

Here is the essential part of our code that loads the images. Can anyone provide an explanation as to technically why this image loading failure happens, and offer a solution that doesn't involve adding paging or "click her to load more" functionality to the image list?

// inside the view that renders the images render: function () {     this.collection.each(this.addOne, this);         return this; }, addOne: function (imgModel) {     var imgView = new App.Views.ImageView({ model: imgModel});     this.$el.append(imgView.render().el); } 

And the render() code for the App.View.ImageView view:

render: function () {     var renderedTemplate= theTemplate(this.model.toJSON());     this.$el.html(renderedTemplate);     return this; } 

And the template used by App.View.ImageView (this gets compiled only once using _.template):

<script type="text/template" id="thumb-template">                   <a href="<%= ImageUrl%>"><img src="<%= ImageUrl%>" /></a>         <div class="delete"></div> </script> 
like image 470
Rafe Avatar asked Jun 09 '14 14:06

Rafe


2 Answers

I believe this is the bug affecting you: https://bugs.chromium.org/p/chromium/issues/detail?id=108055

There's been discussion about it from 2011-2016, and is ongoing. Basically Chrome can't handle a very large number of requests in a short period of time.

Here's what helped a bit for my app:

  • You could add an event handler like img.addEventListener("error",tryAgainLater) but that won't rescue the other resources that fail to load, so your script that loading hundreds of images could interfere with others.
  • Try to cache more of the images to reduce the number of network requests.
  • Use Firefox instead... obviously can't tell customers that.

Here's what did not work:

  • Compositing the images on to a canvas and discarding the individual images. This did not help because it's related to the network requests, not the images stored in memory.
  • Not starting the next request until the previous image is fully loaded. Perhaps this is because it takes time for the connection to actually close or be removed from memory (or some other resource).

Yet to try:

  • Loading the images over HTTP/2 or SPDY where there are many requests but only one connection.
  • In your case you could probably inline the images to avoid making requests. Example from https://css-tricks.com/data-uris/ : <img width="16" height="16" alt="star" src="data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" />
like image 128
WoodenKitty Avatar answered Sep 20 '22 08:09

WoodenKitty


The method toJSON() is very expensive for the browsers as it clones the 'attributes' in the model to return a JSON representation.

... // Return a copy of the model's `attributes` object. toJSON: function(options) {   return _.clone(this.attributes); }, ... 

In some scenarios where I just wanted to display the information of my model, I simply used the 'attributes' property directly, it saves very good time of processing.

Try replacing this line in the ImageView file:

theTemplate(this.model.toJSON()); 

for

theTemplate(this.model.attributes); 

Hope this information helps.

like image 36
Gabo Avatar answered Sep 19 '22 08:09

Gabo