Observer implementation that leverages both behaviours observing a variable and observing for a value. Supports subscribing and withdrawing observers.
var Diffuser = (function() {
return { supply: function() {
return (function() {
var diffusees = [];
var oneTimeDiffusees = [];
var withdraw = function (value) {
var once = function(values) {
var index = values.indexOf(value);
if ( index > -1 ) {
values.splice(index, 1);
return true;
}
return false;
};
var remover = once;
return { from: function(values) {
return remover(values);
}
, entierly: function() {
remover = function(values) {
var index = values.indexOf(value);
if ( index == -1 ) { return false; }
for ( var i = 0; i < values.length; i++ ) {
if ( values[i] === value ) {
values.splice(i, 1);
}
}
return true;
};
return this;
}
, once: function() {
remover = once;
return this;
}};
};
return {
diffuseTo: function(diffusee) {
diffusees.push(diffusee);
return true;
}
, oneTimeDiffuseTo: function(diffusee) {
oneTimeDiffusees.push(diffusee);
return true;
}
, withdraw: function(diffusee) {
return withdraw(diffusee).from(diffusees);
}
, withdrawOneTimeDiffusee: function(diffusee) {
return withdraw(diffusee).from(oneTimeDiffusees);
}
, diffuse: function(diffused) {
var diffuseFunction = function() {
diffusees.forEach( (diffusee) => { (function() { diffusee(diffused); })(); });
};
var oneTimeDiffuseFunction = function() {
for ( var i = 0; i < oneTimeDiffusees.length; i++ ) {
var diffusee = oneTimeDiffusees.pop();
if ( !(function() { return diffusee(diffused); })() ) {
oneTimeDiffusees.push(diffusee);
}
}
};
setTimeout( function() {
diffuseFunction();
oneTimeDiffuseFunction();
}, 0);
}
};
})();
} };
})();
Usage example:
var crunch = (function() {
var oneTimeListener = (function() {
var aLetter = “a”;
var theCodeToRunForALetter = () => {};
return (listenedValue) => {
if ( listenedValue != aLetter ) { return false; }
theCodeToRunForALetter();
return true;
};
} )();
var listener = (value) => {};
var observed = Diffuser.supply();
observed.diffuseTo(listener);
observed.diffuseTo(oneTimeListener);
return (toCrunch) => {
Array.from(toCrunch).forEach( (letter) => { observed.diffuse(letter); } );
};
})();
crunch("some text to crunch");