mikesol / purescript-bolson

An FRP application builder

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Experiment with alternative approaches to item removal

mikesol opened this issue · comments

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 via setInterval (probably the latte would be faster) that immediately calls requestIdleCallback.
  • 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.

When avoiding descheduling altogether, the results are really good
Screen Shot 2022-05-13 at 6 20 29 AM
Screen Shot 2022-05-13 at 6 19 43 AM

Descheduling every second:
Screen Shot 2022-05-13 at 7 05 12 AM
Every 5 seconds (even better):
Screen Shot 2022-05-13 at 7 08 24 AM

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