logoalt Hacker News

dasherswyesterday at 11:27 PM1 replyview on HN

Thanks for your insights. I was originally hesitant about the performance of proxies, too, but they turned out to be great. The benchmarks (https://geajs.com/benchmark-report.html) also show good results. Both in terms of memory and CPU cycles, even though proxies are obviously adding an overhead, it's not day and night (https://jsben.ch/proxy-vs-object-performance-benchmark-dtxo6 is a good test for this). With a proxy, you can set a property 25 million times per second (on my M4 Max machine in Safari) with only 4% perf loss vs defineProperty, and Chrome is about half the perf with 20% loss vs defineProperty. So, still, 12.5 million setters per second is pretty good. Of course if your use case demands more performance, nothing beats a hand-optimized vanilla JS code.

Since Gea doesn't rerender the template _at all (well, for the most part, at least)_, in theory we wouldn't really gain much from getter memoization, mainly because we create proxy observers for computed values that update the DOM in place only when the underlying value updates.

And since stores are plain old JS classes, there's no need for an "async store" concept. Just update a value in the store whenever you want, track its loading state however you want, either synchronously or asynchronously, and the observers will take care of them. If you refer to another pattern that I'm not aware of, please let me know.


Replies

Acmeontoday at 12:56 AM

On my computer, the linked benchmark gives the following results.

Object.defineProperty getter: 82M ops/sec, Proxy getter 32M ops/sec => proxy get is 2.56x slower.

Object.defineProperty setter: 14M ops/sec, Proxy setter: 12M ops/sec => proxy is 1.17x slower.

However, in my simple self written benchmark that compares the time it takes to sum the property values (i.e., getter) of 100 million proxies vs plain objects, the result is that the proxies are 13x slower.

When benchmarking the setting of the property value of the 100 million proxies vs plain objects, the result is that the proxies are 35x slower.

My simple benchmark gives results that significantly deviate from the linked benchmark. Regardless, the relevance of the performance implications of proxies should be evaluated on a case by case basis.

Regarding the memoization, I was primarily referring to accessing the getter multiple times (i.e., not necessarily in DOM rendering), which can cause unnecessary computation in Gea (as far as I can tell). In my envisaged use cases, this could often lead to problems (with, e.g., large data sets).

My issues with async mainly relates to developer convenience (i.e., managing the async stuff can be cumbersome). For example, one can use await in a top-level module statement, but not in a class getter. There has been some relevant discussions about this in the context of Svelte, see, e.g., https://github.com/sveltejs/svelte/discussions/15845, https://www.youtube.com/watch?v=1dATE70wlHc and https://www.youtube.com/watch?v=e-1pVKUWlOQ.

Consider this conceptual example (i.e., async computed value):

  store0.url = "...";
  store1.res = await fetch(store0.url);
How would this be accomplished in Gea so that reactivity would be preserved (i.e., mutating store0.url would trigger a new fetch)? Is it possible to "listen" to changes to store0.url and handle the async code?
show 1 reply