Experiment with alternative approaches to item removal
mikesol opened this issue · comments
Mike Solomon commented
In the DynamicChildren
branch of entity, one pattern I'm seeing emerge is to do bang (insert logic) <|> delay sensibleOffset remove
. This is generally fine, but when there are 100s or 1000s of elements being inserted in a very short timeframe, the result is that many setTimeout
-s being called, which has poor performance.
Because all we're doing here is cleanup, it's possible to have a different setup that works roughly like this:
- Instead of a timeout, we have some sort of data structure with bins, where each bin corresponds to a timeframe.
- We have a loop, either tethered to
requestAnimationFrame
or viasetInterval
(probably the latte would be faster) that immediately callsrequestIdleCallback
. - The callback, when called, goes through as many bins as it cans and thunks their closures.
- We always call
cancelIdleCallback
on the previous callback in case it hasn't been called yet.
Mike Solomon commented
Mike Solomon commented
Descheduling every second:
Every 5 seconds (even better):
Code:
lowPrioritySchedule :: (Number -> Effect Unit -> Effect Unit) -> Number -> Event ~> Event
lowPrioritySchedule f n e = makeEvent \k -> do
void $ subscribe e \i ->
f n (k i)
pure (pure unit)
And then the actual LP schedule
(\k v -> Ref.modify_ (Map.insert k v) unschedule)
- the unscheduling loop
ci <- setInterval 5000 do
Ref.read icid >>= traverse_ (flip cancelIdleCallback w)
requestIdleCallback { timeout: 0 }
( do
n <- unwrap <<< unInstant <$> now
mp <- Map.toUnfoldable <$> Ref.read unschedule
let lr = span (fst >>> (_ < n)) mp
foreachE lr.init snd
Ref.write (Map.fromFoldable lr.rest) unschedule
pure unit
)
w <#> Just >>= flip Ref.write icid