Comments (3)
So just flip the signs of 1
and -1
and it's all good, right? 😆
The data()
mixin attaches to the change
event too, so in your code above, it comes down to which gets fired first.
The view layer isn't really where you'd want to do such a calculation anyway. For instance, if a completed todo is removed, you'll want to decrement the count. And if we load todos from localStorage, we need to redo the whole count, etc. I think I'd rather do it in the model layer.
Incidentally, I played around with schemes to make the SArray() methods have more optimal change behavior. In the end, I just paralleled the standard array methods for two reasons:
-
simplicity of use. If you know how to use the standard Array methods, you pretty much know how to use the SArray ones.
-
applicability. The function doesn't just have to be reversible, it also has to be commutative and expensive enough to matter. In this case, I'm guessing SArray.reduce() would take you well beyond 10k todos before taking longer than a 60hz frame refresh, maybe even 100k.
... but it's still an interesting problem.
Off the top of my head:
-
I'd make the completed signal a
sum
signal, which is a variant of a data signal which, instead of a new value, takes a function to transform the old value to the new. Socompleted(x => x + 1)
instead ofcompleted(S.sample(completed) + 1)
. This isn't part of core S, but can be implemented in a few lines of code. Let me know if you're curious how to do so. -
I'd use
mapS()
to create a computation for each todo which incrementedcompleted()
when appropriate and usedS.cleanup()
to schedule the corresponding decrement. Essentially, the computation creates a side-effect by incrementing completed, which it needs to clean up when it re-runs.
So something like (untested):
const count = S.sum(0),
inc = () => count(c => c + 1),
dec = () => count(c => c - 1);
...
todos.mapS(todo => todo.done() && (inc(), S.cleanup(dec)));
from s.
I'm absolutely interested in exploring various options. I'm still learning about this whole field of client-side reactivity, vdom, JSX, etc., so please bear with me!
An explicitly commutative variant of reduce which accepts a TAcc merge(TAcc acc, TItem original, TItem current)
might solve this problem. So a completed count could be defined as:
todos.creduce(
(acc, x) => acc + (x.done() ? 1 : 0),
0,
(acc, o, x) => acc - (o.done() ? 1 : 0) + (x.done() ? 1 : 0))`.
Or you could overload the regular reduce based on the extra argument for merge. I got this idea from the Concurrent Revisions work at Microsoft which uses similar merge functions to ensure incremental and deterministic concurrent execution.
The only problem is that you'd need to store the original value of any changed signal while a reaction/recomputation is underway, just in case they're needed for a creduce merge. Upside being, you can now support commutative and incremental reduction on an opt-in basis.
I had also considered special sum()
and count()
methods, but I think creduce()
is a more general solution, ie. sum(f) = creduce((acc,x) => acc+f(x), 0, (acc,o,x) => acc-f(o)+f(x))
, count(f) = creduce((acc,x) => acc+(f(x) ? 1 : 0), 0, (acc,o,x) => acc - f(o) + f(x))
.
I started exploring this question based on a thread where I was discussing various options like MobX and such, and the incremental reduce/completed count issue with S.js came up. So I'm not sure I'd do it this way either, but it ought to be possible and simple to do so.
P.S. Your link to index.d.ts on the S-Array repository should be a link to index.ts.
P.P.S. Alternately, you could define a global map that maps typeof x
to merge functions for that type, but I'm not sure this would work given JS's dynamic types and heterogeneous collections.
P.P.P.S. As another possibility, you can define creduce to always return some known commutative type, creduce(f : TItem->Number, seed, merge:Number->Number->Number)
. So all reduction happens via merge
after mapping to a known commutative type, like Number. So counting completed tasks would then simply be todos.creduce(x => x.done() ? 1 : 0, 0, (acc, o, x) => acc - o + x)
.
from s.
Yeah, I was puzzling over how a more general utility could be constructed. My thought was a little like your last form but with three functions: one to extract a value from the item, one to add it to the accumulator, one to subtract.
creduce<T, I, A>(f : T => I, add : (A, I) => A, sub: (A, I) => A, seed : A)
todos.creduce(x => x.done() ? 1 : 0, (acc, x) => acc + x, (acc, x) => acc - x, 0)
I think it'd need three functions, not just two, because it'd have to deal with the case where a value left the collection, not just updated.
from s.
Related Issues (20)
- Karma / Jest testing HOT 9
- Just took it for a first drive....
- Push to array data signal HOT 1
- Creating computations when resolving Promises HOT 2
- Maps HOT 12
- Are subclocks generally available? HOT 4
- Computations creating signals HOT 10
- Make methods treeshake-able HOT 3
- Root + Async = Headaches HOT 5
- Cleanup single computation HOT 1
- S.value multiple updates with no listeners fail HOT 1
- Conditionally triggering downstream computations HOT 3
- Can this nested computation behavior be explained? HOT 2
- Recommended way to deal with "Runaway clock detected"? HOT 1
- Handling Nested Computations under Branching Logic HOT 13
- Why prevent signals from setting different pending values in a single clock tick? HOT 1
- how to implement the rxjs .scan operator with S.js? HOT 7
- Local state inside effect / hooks HOT 2
- Compute value with prev != next check
- cleanup and update phases are intermingled HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from s.