@kangax: :-)
@all: I should mention that I don't know for sure that this create-a-
closure-within-a-closure idiom works in terms of the garbage
collectors out there; I've always intended to go find out because it
seems like there's a chain involved and it wouldn't necessarily be
broken by doing that. I'd be really interested in any references
folks have to empirical results on that, since as Manu points out, it
might matter in terms of memory use. A quick-and-dirty test in FF2
for Windows suggests that FF doesn't release the context in this
scenario:
var keeper = null;
function executionContextTest()
{
var a;
var n;
a = new Array();
for (n = 200000; n > 0; --n)
{
a[n] = new Date();
}
// keeper = function() {
// alert('This is the keeper function');
// };
keeper = (function() {
return function() {
alert('This is the keeper function');
}
})();
}
(Where I trigger executionContextTest via a button.) The commented-
out code would definitely preserve the execution context and therefore
the array, but the second example is using the closure-creates-a-
closure idiom. FF seems to keep all of the execution contexts alive
(and therefore preserve the array) in this case as well. When I run
this, FF's memory use goes up by about 19MB, and doesn't come down
again until I use another button to release the keeper reference (and
then an alert to jog the garbage collector). If I don't create the
closure at all, the memory is reclaimed as soon as
executionContextTest completes (without having to jog the garbage
collector).
But again, this was not in any way a scientific test. If anyone can
point me at some... :-)
@Manu: Don't let this bother you in cases where you're not keeping a
reference to the closure, that's the only time the issue of keeping
the execution contexts alive comes up. Use-and-discard closures are
not a problem (and very useful).
--
T.J. Crowder
tj /crowder software / com
On Feb 23, 12:43 pm, kangax <[EMAIL PROTECTED]> wrote:
> Wow, that's one thorough explanation.
> Thanks T.J.
>
> On Feb 23, 5:01 am, "T.J. Crowder" <[EMAIL PROTECTED]> wrote:
>
> > Hi,
>
> > > Closures is something that (can) cause memory leaks, right?
>
> > That's a complex topic. :-) Closures inherit, and therefore preserve
> > for their lifecycles, all of the local variables and parameters of the
> > functions they're defined in. If the closure is used immediately and
> > discarded, you don't much care. If you're going to retain a reference
> > to the closure (for instance, an event handler, or a dynamically-
> > created instance method), then you want to be aware of this. Here's
> > an example of the latter case:
>
> > function myNiftyMethod(param)
> > {
> > var v1, v2, v3;
>
> > // ... do something ...
>
> > // create and retain a closure to do something
> > this.thingy = function() {
> > // ... some code for the closure ...
> > };
>
> > }
>
> > When myNiftyMethod is executed, it creates a closure and remembers it
> > on the object instance as this.thingy. Since the closure holds a
> > reference to all of myNiftyMethods local variables and params (even
> > though it doesn't use them), and since the object instance keeps a
> > reference to the closure, 'param', 'v1', 'v2', and 'v3' all live on
> > for as long as the closure does. (Modulo cool JavaScript engine
> > optimisations, which I don't think are common yet and are harder for
> > the engine to do than it would at first seem.)
>
> > So closures can have memory *implications*; if you understand how they
> > work, though, and get used to some idioms around them, you won't cause
> > memory leaks (barring JavaScript engine bugs).
>
> > This is rambling a bit, but here's an example of the case where you're
> > using the closure immediately and discarding it:
>
> > function myNiftyMethod(someArray)
> > {
> > var v1, v2, v3;
>
> > // ... do something ...
>
> > // create and retain a closure to do something
> > someArray.each(function(item) {
> > item.doSomethingCool();
> > });
>
> > }
>
> > You don't keep a reference to the closure used in the each() method,
> > so you don't have to consider the implications of myNiftyMethod's
> > parameters and variables being retained. And it's a very powerful and
> > expressive way to deal with each item in the array.
>
> > > - I'm getting lost in how you constructed the onSuccess callback...
>
> > That's easy to do. :-) He's using a closure to construct and return
> > another closure; it's the inner one that gets assigned to the
> > onSuccess handler and retained, the outer one is run immediately and
> > discarded. If you look carefully at the code defining the onSuccess
> > handler, you'll see that the entire outer closure is wrapped in parens
> > -- the opening paren is right after "onSuccess:", and then right at
> > the end of the closure you see the closing paren followed by "(item)"
> > -- that "(item)" tells you he's *executing* the outer closure right
> > then, not just creating it. When it runs, the outer closure creates
> > the inner closure and returns it. *That's* what gets assigned to
> > onSuccess, the reference to the inner closure. The outer closure has
> > only the param it needs (item) and no local variables, so the inner
> > closure only preserves the information it really needs, not all of the
> > local variables where all of this is running.
>
> > Hope this helps,
> > --
> > T.J. Crowder
> > tj /crowder software / com
>
> > On Feb 23, 7:34 am, "Manu Temmerman-Uyttenbroeck"
>
> > <[EMAIL PROTECTED]> wrote:
> > > Hi,
>
> > > Closures is something that (can) cause memory leaks, right?
> > > kangax, would you mind explaining in a bit more detail why you wrote the
> > > code like you wrote it? I'm a bit lost in it. I restructured the code you
> > > wrote a bit...http://pastie.caboo.se/156248
> > > - Is there a reason why you don't write a ';' after the new Ajax.Request
> > > (...)?
> > > - Is there a reason why you don't write a ';' after the
> > > someArray.each(function(item)
> > > { ... })?
> > > - I'm getting lost in how you constructed the onSuccess callback...
>
> > > Thx...
>
> > > Manu.
>
> > > On Fri, Feb 22, 2008 at 11:11 PM, kangax <[EMAIL PROTECTED]> wrote:
>
> > > > Looks like a closure issue to me (solved with another closure).
> > > > Also, is that an array you are iterating over using "for..in" ?
>
> > > > siteListArray.each(function(item) {
> > > > var url = 'functions.php?command=numberOfErrors&site=' + item;
> > > > new Ajax.Request(url, {
> > > > onSuccess: (function(item) { return function(t) {
> > > > $('sidebar_site_div_' + item).update(t.responseText);
> > > > }})(item)
> > > > })
> > > > })
>
> > > > - kangax
>
> > > > On Feb 22, 4:02 pm, Chach <[EMAIL PROTECTED]> wrote:
> > > > > Hi everybody,
>
> > > > > I'm just getting kicked off on prototype and I'm having a problem that
> > > > > I'm hoping to get some help on.. I've had good success with
> > > > > Ajax.Updater, but now I'm trying to use Ajax.Request with the use of
> > > > > its callback abilities. My issue is that I'm trying to get a hold of
> > > > > one of the Element objects in the DOM using $('element'), however the
> > > > > name of the element can vary and so I have to assemble the name using
> > > > > the value in an array. It's almost like the siteListArray[x] does not
> > > > > work in the callback. Is it possible that the callback cannot see a
> > > > > variable that was declared earlier in my code at a global scope?
> > > > > Thanks in advance.
>
> > > > > for (x in siteListArray)
> > > > > {
> > > > > var url = 'functions.php?command=numberOfErrors&site=' +
> > > > > siteListArray[x];
> > > > > new Ajax.Request(url, {
> > > > > asynchronous:true,
> > > > > onComplete: function(transport) {
> > > > > $('sidebar_site_div_' +
> > > > > siteListArray[x]).update(transport.responseText);
> > > > > }
> > > > > });
>
> > > > > }
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Ruby
on Rails: Spinoffs" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/rubyonrails-spinoffs?hl=en
-~----------~----~----~----~------~----~------~--~---