kefirjs / kefir

A Reactive Programming library for JavaScript
https://kefirjs.github.io/kefir/
MIT License
1.87k stars 97 forks source link

skipDuplicates enhancement? #42

Closed sandyplace closed 9 years ago

sandyplace commented 9 years ago

I am new to this stuff so take any suggestions with a grain of salt. I have noticed that skipDuplicates is implemented like:

withOneSource('skipDuplicates', {
  _init: function(args) {
    this._fn = args[0] || strictEqual;
    this._prev = NOTHING;
  },
  _free: function() {
    this._fn = null;
    this._prev = null;
  },
  _handleValue: function(x, isCurrent) {
    if (this._prev === NOTHING || !this._fn(this._prev, x)) {
      this._send(VALUE, x, isCurrent);
      this._prev = x;
    }
  }
});

This can possibly lead to cycles in the subscribers. for example i have a start and an end time and an hours field. I wanted to recalculate the hours when you enter a new end time and recalculate the end when you update the hours. I was trying to use skipDuplicates to prevent this cycle. I believe this would fix it:

withOneSource('skipDuplicates', {
  _init: function(args) {
    this._fn = args[0] || strictEqual;
    this._prev = NOTHING;
  },
  _free: function() {
    this._fn = null;
    this._prev = null;
  },
  _handleValue: function(x, isCurrent) {
    if (this._prev === NOTHING || !this._fn(this._prev, x)) {
      this._prev = x; // set value first to prevent cycle
      this._send(VALUE, x, isCurrent);
    }
  }
});

Any thoughts? BTW: thanks for the great library

rpominov commented 9 years ago

Do you mean something like this?

var a = Kefir.bus();
var b = a.map(function(x) {return x});
a.plug(b.skipDuplicates());

b.log();
a.emit(1);
rpominov commented 9 years ago

Heh, that a little crazy. Never thought of that use case, but now maybe I'll use this myself if got to create a circular dependency. Fixed. Thanks!