Debouncer 
Debouncer module to reduce frequency of function calls to alerts, updates and similar. It supports four different modes:
apply()- For delayed triggers, e.g. to trigger an autocomplete actionimmediate()- For reducing frequency of events, the first event per interval is delivered immediately, e.g. trigger data processing tasksimmediate2()- Similiar to immediate but never delays events, either forwards them or ignores them, e.g. to trigger alert emailsdelay()- Only triggers an event after the timeout period, any further event delays the trigger. E.g. to detect data streams that ended actvitiy
Usage Example
Debouncer.apply(SomeKey, fn() ->
IO.puts("Hello World, debounced will appear in 5 seconds")
end) Debouncer.immediate(OtherKey, fn() ->
IO.puts("Hello World, will appear immediate, but not again within 5 seconds")
end)Behaviour Graph
EVENT E1---E2------E3-------E4----------
TIMEOUT ----------|----------|----------|-
===============================================
apply() ----------E2---------E3---------E4
immediate() E1--------E2---------E3---------E4
immediate2() E1-----------E3-------------------
delay() --------------------------------E4
USE CASE
apply() - Search input field
immediate() - Send email now, but not too freq
immediate2() - Game gun with reload time
delay() - Schedule post-processing jobThis graph represents when the different variants fire an event respectively on a timeline. In code the first line would look like this:
fn ->
Debouncer.apply(SomeKey, fn() -> IO.puts("X1") end, 1000)
Process.sleep(500)
Debouncer.apply(SomeKey, fn() -> IO.puts("X2") end, 1000)
Process.sleep(800)
Debouncer.apply(SomeKey, fn() -> IO.puts("X3") end, 1000)
Process.sleep(900)
Debouncer.apply(SomeKey, fn() -> IO.puts("X4") end, 1000)
Process.sleep(1200)
end.()
> X2
> X3
> X4Shorthands
When using Module-Function-Argument tuples as callbacks (aka mfa) it can be convenient to skip the key and use the mfa itself as key:
# Call later() function immediately with the default 5 second debounce:
Debouncer.immediate({__MODULE__, :later, []})
# Call later() function immediately with 1 second debounce:
Debouncer.immediate({__MODULE__, :later, []}, 1_000)
# Same but in using method binding
Debouncer.immediate(&later/0, 1_000)
# Same but in using method binding
Debouncer.immediate(&later/0, 1_000)NOTE
Do not use in-place fun definitions can not be used in the shorthand, as those create a different key on every.
Example:
# Because (`fn -> 1 end != fn -> 1 end`) don't do this:
Debouncer.immediate(fn -> later() end, 1_000)Installation
The debouncer can be installed by adding debouncer to your list of dependencies in mix.exs:
def deps do
[
{:debouncer, "~> 1.0"}
]
endThe docs can be found at https://hexdocs.pm/debouncer.
Remarks
The delay() behaviour is the same as in Michal Muskalas Debounce implementation https://github.com/michalmuskala/debounce