Nathan Evans' Nemesis of the Moment

A simple stereotypical JavaScript-like “debounce” service for F#

Posted in .NET Framework, F#, Xamarin by Nathan B. Evans on August 9, 2014

I needed a simple way to throttle / debounce a text box on Xamarin.Forms to protect against fast user input events. It is basically a text “Entry” control linked to a “ListView” that displays somewhat expensive to compute results from a SQLite database. When a user is typing in their query it would cause lots of concurrent search queries to be fired off which of course just meant all the queries would run slower and then the results from just one would be used anyway.

So I took a look at the Reactive Extensions library but decided it was a bit too heavy weight for a simple Xamarin mobile app. I tried to find something simpler but came up short. So I took a look at the LoDash.js and Underscore.js libraries to see how these did it but they were littered with mutable and global state – *urgh*.

So I wrote my own using a simple F# agent (MailboxProcessor) and encapsulated it in a type to protect against improper use.

/// Provides a stereotypical JavaScript-like "debounce" service for events.
/// Set initialBounce to true to cause a inject a bounce when first the debouncer is first constructed.
type Debounce(timeout, initialBounce, fn) as self =
    let debounce fn timeout = MailboxProcessor.Start(fun agent -> 
        let rec loop ida idb = async {
            let! r = agent.TryReceive(timeout)
            match r with
            | Some _ -> return! loop ida (idb + 1)
            | None when ida <> idb -> fn (); return! loop idb idb
            | None -> return! loop ida idb
        loop 0 0)

    let mailbox = debounce fn timeout
    do if initialBounce then self.Bounce()

    /// Calls the function, after debouncing has been applied.
    member __.Bounce() = mailbox.Post(null)