curran / model

A functional reactive model library for interactive data visualization.
MIT License
314 stars 43 forks source link

Throttle function from underscorejs or RxJs? #6

Open ronakrrb opened 9 years ago

ronakrrb commented 9 years ago

I like the way you abstracted the binding module from backbone.js. Couple of question though:

  1. Does model.js has observables?
  2. Is it a two way data binding?
  3. How can we add throttle functionality from UnderscoreJS or RxJs?
curran commented 9 years ago

Hi Ronak,

Thank you for your comments, I'm happy to hear you are interested in the library.

  1. Each Model instance is essentially an observable object, in the sense of the Observer pattern. There is no corresponding notion to RxJs Observables though, in Model.js the observable properties are always tied to a model instance (whereas in RxJs the Observables exist independently).
  2. There is no two-way data binding built into Model.js, however it would be fairly straightforward to implement, something like this:
var a = Model();
var b = Model();
a.when("foo", function (foo){
  if(b.foo !== foo){
    b.foo = foo;
  }
});
b.when("foo", function (foo){
  if(a.foo !== foo){
    a.foo = foo;
  }
});
  1. You can use Underscore's throttle function with Model.js, here's an example:
var model = Model();
model.when("foo", _.throttle(function(foo){
  // this code will run at most every 100ms
}), 100);

If you are considering using model.js, you may also want to take a look at https://github.com/curran/reactive-model , which is a rewrite of model.js (work in progress).

ronakrrb commented 9 years ago

Thanks Curran for the explanation.

With respect to the throttle function, is there a way to have it natively inside modeljs to avoid underscore dependency?

Also, it seems there is no data diff mechanism. Does it mean that everytime the data is set, the updates will be called no matter the data is same?

curran commented 9 years ago

It would be possible to add a throttle function to Model.js, but it seems like this goes beyond the scope of what the library provides. If this would make the library a better option for you, feel free to add a throttle function and send a pull request.

Indeed, there is no data diff mechanism. Even if the data is set multiple times to the same value, the updates will be called.

The reason for this is that I noticed a pattern occur frequently in my code that some object is mutated, then set as a model property to cause updates to propagate. If the same mutable object was set previously, then a data diff mechanism would not detect the changes, because the previously held reference would be to the same object. The mutated object would be compared to itself after mutation, so the updates would not be propagated.

In order to implement a data diff mechanism correctly, Model.js would need to do defensive deep copying of the values that are set on properties (or somehow enforce that only immutable objects are used). Then only a diff could be computed. This is straightforward for primitive types (string, number, etc.) or arbitrary JSON structures, but it gets tricky when the value is an object constructed by another library (e.g. a D3 selection). To avoid the headache of defensive copying, I made the updates propagate no matter what the values are.

However, for certain use cases, you could implement the data diff checking in your application code, before you set the value on the model. That might look like this:

if(model.x !== newX){
  model.x = newX;
}
ronakrrb commented 9 years ago

Interesting. Why do you have to do the defensive copying? Just wondering if that could be done in the setter function only.