Hacker News new | ask | show | jobs
Icaro – Smart Javascript object observer, ideal for batching DOM updates (github.com)
58 points by gianlucaguarini 3274 days ago
6 comments

Nice, I made something really similar but found it had a bunch of issues. Some of which I don't see addressed here.

When setting an object or array, it will always trigger since the equal comparison will return false even if they have the same { key: value } pairs:

    target[property] !== value
Speaking of which, sub-properties are not being listened to from the root (only if manually listened to on the sub-object):

    obj.foo = { bar: 'baz' }; // triggers
    obj.foo.bar = 'whatever'; // never triggers the base listener
The only realistic automatic way to listen to them is to add a trap for the get, which will proxify the return value if it's an object or array. This has it's own set of errors and turns into a nasty set of edge cases, which is the main reason I never got to release what I was doing. I see in Icaro you Proxify it manually and adding some props on the setter, which leads to this not working as expected:

    const obj = icaro({ foo: { bar: 'baz' } });
    obj.foo.bar = 'baz2';  // Nothing triggers
The array example is a little weird.

    // no events here
    arr.map(v => v + '-meh')
Since `.map` doesn't mutate the array in the first place, surely no one would expect observation events to occur anyway?
now array methods dispatch as well in v1.1.0 I also thought it was weird thanks for your feedback anyway
Indeed. This functionality really worries me.

Why would a non-mutation trigger listeners?

you are absolutely right, map doesn't belong to the mutational methods. Fixed in v1.1.1 thank you for your feedback
Isn't this just queuing up the actual, real work on the event loop?

Of course its faster to call setImmediate a bunch of times to defer work, than it is to actually DO the work. It is useless to compare a synthetic benchmark for what is fundamentally a task that involves drawing something to the screen, without measuring the time it takes to finish all those tasks. The actual performance will, of course, be determined by how many DOM mutations are occurring, and the relative layout complexity of each. There will be a benefit for lots of really small, expensive mutations that could be batched together, but who designs their applications like that? Oh, wait...

At least, that's my understanding of looking at the source for a few minutes. Maybe I'm missing something, but I don't see any real algorithm at work here, just work that is shifted around to make a benchmark look good.

A better benchmark would be to use this in a real world, non-trivial use-case somehow and measure the framerate. But I can save you the effort: It's not going to win out over a well designed application that does direct DOM manipulation. Period.

But is Icaro more on listening changes on javascript objects, in a general manner, better than just the DOM ones?

I think that this light lib could be actually a cool toy to use if you need for example to do some simple app state listened manipulations on the node backend side.

Otherwise, that is true, I would maybe still prefer to use frontend side some well-designed frameworks like redux-Rx or redux-react

Last time I tried Proxies, their performance wasn't very good. It would be great to see a few benchmarks.

What advantages would this give you over using persistent data structures [0] with memoized selectors? When using immutable data structures, you can shift the responsibility of providing updates up to the caller. In my experience, that usually means code that's easier to debug and test.

[0] https://en.wikipedia.org/wiki/Persistent_data_structure

Here you can see some bench results comparing the most popular reactive javascript libs https://github.com/GianlucaGuarini/reactive-libs-bench icaro included
Why is icaro so much more performance? It's two orders of magnitude faster than the other frameworks if I'm reading the results correctly.
please check the readme file https://github.com/GianlucaGuarini/icaro#performance there it's explained
Could you elaborate on the perf issues? You mean synthetic tests, right?
If this is meant to target modern browsers, what's the use of this check and fallback for IE's obsolete API?

    if (global.addEventListener) {
      global.addEventListener('message', onGlobalMessage, false);
    } else {
      global.attachEvent('onmessage', onGlobalMessage);
    }
Well that's a fork of https://github.com/YuzuJS/setImmediate so it must be removed! Would you mind making a pull request?
> Would you mind making a pull request?

I do mind, so no thanks. I've written at length about why[1][2].

I'm not using the project, but you can consider the feedback in my last comment as a bug report if you like.

1. http://www.colbyrussell.com/2015/05/31/git-and-its-hubs.html

2. https://github.com/colbyrussell/keeping-a-low-profile-on-git...

I sort of understand why you want to avoid GitHub, thank you for sharing those links. All in all though to make a small pull request like the one in question, it takes about 2 minutes and three clicks to do so.

Not that you should do so if you don't want to, but this is a good thing for OS projects. The barrier to entry and contribute is non-existent - if you want to fix something small just press 'edit', make your changes in the browser and press 'submit merge request'.

No cloning, no local installs, no fuss. You can do it from your phone, on a bus.

The parent one seems to handle more, nested properties and batching?
hmm not sure what batching means in this context but nested property works.
ehy thanks for linking to your project it looks great! Regarding the batching strategy icaro smartly groups the object changes via setImmediate helping in case you need to change many properties on the same object for example:

obj.name = 'foo' obj.surname = 'bar'

in this case icaro will dispatch only one event optimizing the listeners to avoid unnecessary redundant events