Custom Stateful with hitched observer callback

Description

This example has a custom Stateful which clears the callback reference when the

Stateful fix

Set the callback to null and let the handle's unwatch and remove point to an empty function. The handle has been removed, but if it's been called again nothing will happen. The suggested fix is done in watch() of Stateful:

// TODO: Remove unwatch in 2.0
var handle = {};
handle.unwatch = handle.remove = function(){
	var index = array.indexOf(propertyCallbacks, callback);
	if(index > -1){
		propertyCallbacks.splice(index, 1);
	}
	
	// FIX:
	// no need to ref callback in closure, let's bind an empty functionn
	// as we already removed it from the callbacks
	callback = null;
	handle.unwatch = handle.remove = function(){};
	handle = null;
};

Verify the behavior

Open this page in Google Chrome. Open Activity monitor (shift + escape) to observe memory usage. Notice that it drop after a little while. Open web inspector. Take a heap snapshot. Click on the heap snapshot. Expand the "(string)" node and you won't the long string at the top.

You can also verify it for IE and FF if you look at the memory for the process in activity monitor. It should rise and then drop again.

Source

// global scoped variable to simulate Stateful that lives longer than the observer 
var globalmodel;

require([
    "custom/Stateful",
    "dojo/_base/lang", 
    "dojo/domReady!"
], function(
    Stateful,
    lang
) {
    // model to observe
    globalmodel = new Stateful();
    
    // the observer with a 50,000,000 character long string property
    var observer = {
        LONGSTRINGPROPERTY: Array(5e7).join("."),
        modelValueChanged: function() { }    
    }; 
	
    // observe handle
    var handle = globalmodel.watch("prop", lang.hitch(observer, observer.modelValueChanged));	

    // remove the handle
    handle.remove();
});