Home
Developers

Developers

  • Documentation
    • Developer Guide
    • API Reference
    • Style Guide
    • How-To
    • Troubleshooting
  • Submit a Flake
  • Support

Pageflakes How-To and Troubleshooting Guide

  • Manage Flake Instances
  • Server-Side Scripting
  • Auto-Save Settings
  • Storing an Array into a Profile
  • Using CSS
  • Access Web Services from Flakes
  • Flake Development Tools
  • Troubleshooting
    • Using the "id" element correctly
    • Using XMLHttpRequest
    • Issues with Internet Explorer, Firefox and Opera
    • Use CDATA inside script blocks
    • Avoid memory leaks and understand 'this'
    • Minimize processing in load()
    • Do not use alert()
    • Do not use <form> elements
Home » Documentation » How-To » Troubleshooting

Avoid memory leaks and understand 'this'

Normally we know this refers to the current instance of the class. So, we write scripts like:

this.load = function()
{
 this.a = 10;
}

However, if the load function is called from an event or a timer, then this actually means the control from which the event is fired or the timer, not the instance of the class. The same applies to web service callbacks or any asynchronous JavaScript callbacks. In that case, this.a will no longer be a variable inside the class.

This code shows another problem:

function what_is_this()
{
  this.load = function(instance)
  {
    this.resultDIV = $('result');
    SomeWebService.DoSomething( 10, 20, 30, onComplete );
  }
  function onComplete(result)
  { 
    this.resultDIV.innerHTML = result; // FAILS
    this.done(); // FAILS
  }
  this.done = function()
  {
    alert("I never get called");
  }
}

This code will fail because this is no longer the instance of the class; instead it's some object from the Atlas framework which called the onComplete function.

One easy way to work around this problem is to save the value of this in a variable (self is commonly used):

function what_is_this()
{

var _resultDIV; var self = this; this.load = function(instance) { _resultDIV = $('result'); SomeWebService.DoSomething( 10, 20, 30, this.onComplete ); } this.onComplete = function(result) { _resultDIV.innerHTML = result; self.done(); } this.done = function() { alert("I do get called"); } }

While this works, it will leak memory because a closure is formed. Here’s how:

Once load() has been called and returned, onComplete cannot be removed because the global context has a reference to it (to call it back). In addition, the onComplete() function has a reference to the global context because it refers to the self variable, contained in the what_is_this object, which is created in the global context. Because of the circular reference, the memory is never freed, which quickly causes significant performance degradation.

To solve this issue, eliminate such closures:


function what_is_this()
{
  this._resultDIV = undefined; 
  this.load = function(instance) 
  { 
    this._resultDIV = $('result'); 
    this.SomeWebService.DoSomething( 10, 20, 30, PF.F(this, this.onComplete)); 
  }
  this.onComplete = function(result) 
  { 
    this._resultDIV.innerHTML = result;  
    this.done();  
  } 
  this.done = function()
  { 
    alert("I do get called"); 
  }
} 

In the example above, the self variable is eliminated, thus removing the closure. In addition, the PF.F function is used when setting the callback, to ensure that the value of this is correct when onComplete is invoked.

The code shown below improves the example even further by using prototypes. The advantage of prototypes is that if we have multiple instances of the what_is_this class created, the functions would be instantiated only once, resulting in performance savings.


function what_is_this()
{
  this._resultDIV =
  undefined; 
}
what_is_this.prototype.load = function(instance) 
{ 
  this._resultDIV = $('result'); 
  this.SomeWebService.DoSomething( 10, 20, 30, PF.F(this, this.onComplete)); 
} 
what_is_this.prototype.onComplete = function(result) 
{ 
  this._resultDIV.innerHTML = result;
  this.done();
} 
what_is_this.prototype.done = function()
{ 
  alert("I do get called"); 
}

Similarly, if an event handler needs to call one of the prototype functions, it must use the PF.F shortcut to ensure that the event handler is called with the correct value of this.

‹ Use CDATA inside script blocksupMinimize processing in load() ›
»
  • Printer-friendly version