# jQuery Lightbox Maximum call stack size exceeded



## jervinguy (Oct 3, 2012)

Good day, please see this example. Click first image thumb, then scroll through, perhaps until the 13th image. By this point, the gallery often stops working, returns to the thumbnails, which have also stopped working (i.e. bringing up the lightbox overlay) and merely link to the original image:

http://www.anunexpectacle.com/aptart/gallery/projects/

Console shows this output:

Uncaught RangeError: Maximum call stack size exceeded

s
m
f.fn.extend.find
e.fn.e.init
e
Lightbox.updateDetails
Lightbox.showImage
(anonymous function)
Something similar is touched upon here: Fancybox Recursion Error

How can I stop this?! Thanks, Matt


----------



## Ent (Apr 11, 2009)

It doesn't seem to be a recursion issue; I imagine it's just because it tries to fetch each image from the server into its own new image object (line 196 in lightbox.js), and those objects have a knack for eating into your available memory. 
I'd be looking for a way to reuse the same image object and change the image it holds.

If this doesn't make any sense, let me know and I'll rephrase it.


----------



## jervinguy (Oct 3, 2012)

Thanks for your quick response, it's very reassuring.

I understand what you say. My js is pretty weak though, so I may have trouble implementing. Perhaps there is a way of accessing already instantiated image objects and flushing them from memory every time changeImage is run? They don't need to be there, I suppose.

I would probably try and hack this by:

1) Finding a way to reference the image object list (if it is a list, whatever it is or can be represented as).
2) Referencing it at the beginning (or perhaps end) of changeImage().
3) Find a way to flush objects from that object list at the same point.

What do you think?

I'm sure there is a more elegant solution, but this has crept up and bitten me at the very end of a website build and threatens to destroy all sense of inner peace. If I can make it work at all, I will be extremely relieved.

Thanks again!


----------



## Ent (Apr 11, 2009)

jervinguy said:


> I understand what you say. My js is pretty weak though, so I may have trouble implementing. Perhaps there is a way of accessing already instantiated image objects and flushing them from memory every time changeImage is run? They don't need to be there, I suppose.


That's the peculiar thing, I'd think such an object should be destroyed as soon as it goes out of scope a few lines later. What about creating preloader as a single global variable (perhaps rename it something less likely to clash)? Instead of worrying about destroying it, just don't make any more!


----------



## jervinguy (Oct 3, 2012)

So I tried this (below), locally. Was your idea that, if var preloader is global, its content would be replaced each time changimage is run, and there would only be one such variable, rather than a whole new, function-local-scoped var preloader being created every time change image is run? It didn't seem to work though, same error.

Any other thoughts? Thanks again for helping me, I'm drowning a bit here.

var preloaderer;

Lightbox.prototype.changeImage = function(imageNumber) {
var $image, $lightbox,
_this = this;
this.disableKeyboardNav();
$lightbox = $('#lightbox');
$image = $lightbox.find('.lb-image');
this.sizeOverlay();
$('#lightboxOverlay').fadeIn(this.options.fadeDuration);
$('.loader').fadeIn('slow');
$lightbox.find('.lb-image, .lb-nav, .lb-prev, .lb-next, .lb-dataContainer, .lb-numbers, .lb-caption').hide();
$lightbox.find('.lb-outerContainer').addClass('animating');
preloaderer = new Image;
preloaderer.onload = function() {
$image.attr('src', _this.album[imageNumber].link);
$image.width = preloaderer.width;
$image.height = preloaderer.height;
return _this.sizeContainer(preloaderer.width, preloaderer.height);
};
preloaderer.src = this.album[imageNumber].link;
this.currentImageIndex = imageNumber;
};


----------



## Ent (Apr 11, 2009)

I was thinking more along the lines of this:


```
var preloaderer = new Image;;
 
    Lightbox.prototype.changeImage = function(imageNumber) {
      var $image, $lightbox,
        _this = this;
      this.disableKeyboardNav();
      $lightbox = $('#lightbox');
      $image = $lightbox.find('.lb-image');
      this.sizeOverlay();
      $('#lightboxOverlay').fadeIn(this.options.fadeDuration);
      $('.loader').fadeIn('slow');
      $lightbox.find('.lb-image, .lb-nav, .lb-prev, .lb-next, .lb-dataContainer, .lb-numbers, .lb-caption').hide();
      $lightbox.find('.lb-outerContainer').addClass('animating');
      preloaderer.onload = function() {
        $image.attr('src', _this.album[imageNumber].link);
        $image.width = preloaderer.width;
        $image.height = preloaderer.height;
        return _this.sizeContainer(preloaderer.width, preloaderer.height);
      };
      preloaderer.src = this.album[imageNumber].link;
      this.currentImageIndex = imageNumber;
    };
```
Note that I haven't tested it.


----------



## jervinguy (Oct 3, 2012)

That doesn't appear to work either. I'll keep fiddling. If you have any more ideas, I'd be so grateful to hear them.
Thanks


----------



## jervinguy (Oct 3, 2012)

Running console log statements in the code to see the state of the relevant variables as the script runs seems to show that these variables are being updated. I don't know how the memory is being sapped. I put these console logger commands into the code:

preloaderer = new Image;
line 196 console.log(preloaderer) 
line 197 console.log($image) 
preloaderer.onload = function() {

console output looks like this:

lightbox.js:196
[
<img class=​"lb-image" style=​"display:​ inline-block;​ " src=​"http:​/​/​localhost/​aptart/​wp-content/​uploads/​2012/​10/​painty-hand-copy11.jpg">​
]

lightbox.js:197

<img src=​"http:​/​/​localhost/​aptart/​wp-content/​uploads/​2012/​10/​painty-hand-copy10.jpg">​

lightbox.js:196

[
<img class=​"lb-image" style=​"display:​ none;​ opacity:​ 0.986775;​ " src=​"http:​/​/​localhost/​aptart/​wp-content/​uploads/​2012/​10/​painty-hand-copy10.jpg">​
]

lightbox.js:197

<img src=​"http:​/​/​localhost/​aptart/​wp-content/​uploads/​2012/​10/​painty-hand-copy9.jpg">​

lightbox.js:196

[
<img class=​"lb-image" style=​"display:​ none;​ opacity:​ 0.9964;​ " src=​"http:​/​/​localhost/​aptart/​wp-content/​uploads/​2012/​10/​painty-hand-copy9.jpg">​
]

lightbox.js:197

<img src=​"http:​/​/​localhost/​aptart/​wp-content/​uploads/​2012/​10/​painty-hand-copy8.jpg">​

lightbox.js:196

[
<img class=​"lb-image" style=​"display:​ none;​ " src=​"http:​/​/​localhost/​aptart/​wp-content/​uploads/​2012/​10/​painty-hand-copy8.jpg">​
]


----------



## Ent (Apr 11, 2009)

I'm not really sure now. It's certainly not recursive, since the function isn't calling itself and only runs once per click. 

A Heap snapshot made with the Google Chrome profiler says that 5.26 MB is allocated when the first image is loaded. That builds up to around 10 MB by the time it actually finally crashes. Exactly where these megabytes appear is as much a mystery to me as it is to you.


----------



## jervinguy (Oct 3, 2012)

All the stranger given that the main image repeating in that gallery is just 36.6kb in size. I'm perplexed.

Would be so keen to hear if you have any other ideas.

Thanks


----------



## Ent (Apr 11, 2009)

I'm afraid that I can't think of anything right now; perhaps someone else will.


----------



## jervinguy (Oct 3, 2012)

I think I cracked it. Embarassingly, it was a piece of my own code, elsewhere in the script, that I'd stuck in a while back. However, I worked it out by looking more closely at the functions stated in the original error, above. It was in UpdateDetails.

Thanks for trying to help though. On this occasion, your moral support got me through the day, and I learned a lot along the way.


----------

