dphfox / Fusion

A modern reactive UI library, built specifically for Roblox and Luau.
https://elttob.uk/Fusion/
MIT License
530 stars 91 forks source link

Allows developers to specify limits on internal consistency #353

Open dphfox opened 1 week ago

dphfox commented 1 week ago

Fusion currently mandates that the entire reactive graph is kept internally consistent, and always updates in a single atomic step. This is great for developer experience, and should absolutely remain default behaviour, but sometimes it can be okay to sacrifice consistency to allow work to be split across multiple update cycles.

One way we could explore this is by introducing wrapper state objects that are allowed to become inconsistent with the rest of the graph, retaining their previous value when they're evaluated as part of an update step. If there's time to spare within the update step, these objects can pull a new value from the state object they wrap and update their dependents.

A simple example:

local a = scope:Value(2)
local b = scope:Value(5)
local sum = scope:Computed(function(use)
    return use(a) + use(b)
end)
local sum = scope:Inconsistent(sum)
local sumIsEven = scope:Computed(function(use)
    return use(sum) % 2 == 0
end
print(peek(sumIsEven)) --> false

If the update cycle is taking too long, the Inconsistent object is allowed to fall out of lockstep with the rest of the reactive graph, meaning graph objects dependent on it won't run:

doLotsOfWork()
a:set(10)
b:set(12)
print(peek(sumIsEven)) --> false
task.wait(1) -- wait for intensity to die down
print(peek(sumIsEven)) --> true