miso
Copyright(C) 2016-2026 David M. Johnson
LicenseBSD3-style (see the file LICENSE)
MaintainerDavid M. Johnson <code@dmj.io>
Stabilityexperimental
Portabilitynon-portable
Safe HaskellNone
LanguageHaskell2010

Miso.Subscription.Util

Contents

Description

Overview

Miso.Subscription.Util provides createSub, the building block used by every subscription in Miso.Subscription. It handles the acquire-use-release lifecycle of an external resource (an event listener, an animation-frame callback, etc.) using bracket so the resource is always cleaned up when the Component unmounts, even if an exception is thrown.

It also provides rAFLoop, a requestAnimationFrame loop built on createSub whose callback re-schedules itself every frame. It is the basis of rAFSub, rAFSubElapsed and canvasSub. See Note [rAFLoop teardown].

Quick start

Use createSub to build a custom subscription from any pair of acquire/release actions. The subscription sleeps between polls and relies entirely on the acquire step to register whatever callbacks deliver events to the sink:

import Miso.Subscription.Util (createSub)
import Miso.Effect (Sub)
import qualified Miso.Runtime.Internal as FFI

-- Custom subscription: fire an action whenever the window is resized
resizeSub :: (Int -> action) -> Sub action
resizeSub toAction sink = createSub acquire release sink
  where
    acquire =
      FFI.windowAddEventListener "resize" $ \_ -> do
        w <- FFI.windowInnerWidth
        sink (toAction w)
    release cb =
      FFI.windowRemoveEventListener "resize" cb

How it works

createSub acquire release sink runs:

bracket acquire release (\_ -> forever (threadDelay 1000_000_000))

The forever loop keeps the subscription thread alive by sleeping in very long increments. All actual work is done inside callbacks registered during acquire, which call sink directly. release is guaranteed to run (via bracket) when the component teardown kills the thread.

See also

Synopsis

Utilities

createSub Source #

Arguments

:: IO a

Acquire resource

-> (a -> IO b)

Release resource

-> Sub model action 

Utility function to allow resource finalization on Sub.

rAFLoop Source #

Arguments

:: IO (Double -> IO ())

Builds the per-frame handler; runs once at start

-> Sub model action 

A self re-scheduling requestAnimationFrame loop, as a Sub.

The IO action runs once, when the Sub starts, and builds the per-frame handler; it is the place to acquire anything the handler needs (a canvas context, IORefs for timing state, ...). The handler then receives the frame's DOMHighResTimeStamp in milliseconds, every frame, until the Sub is stopped.

A single callback is used for the whole loop; it is freed when the Sub stops. See Note [rAFLoop teardown].

Since: 1.15.0.0