아주 순진하고 단순한 솔루션은 원시 프로세스를 사용할 수 있습니다.
defmodule Debounce do
def start(fun, timeout) do
ref = make_ref()
# this function is invoked when we wait for a next application
recur = fn recur, run ->
receive do
^ref ->
# let's start counting!
run.(recur, run)
end
end
# this function is invoked when we "swallow" next applications
# and wait until we finally apply the function
run = fn recur, run ->
receive do
^ref ->
# let's reset the counter
run.(recur, run)
after
timeout ->
# time is up, let's call it for real & return to waiting
fun.()
recur.(recur, run)
end
end
pid = spawn_link(fn -> recur.(recur, run) end)
fn -> send(pid, ref) end
end
end
이의이 예 그러나
iex> f = Debounce.start(fn -> IO.puts("Hello"), 5000)
iex> f.()
iex> f.()
# wait some time
Hello
iex> f.() # wait some time
Hello
을 보자, 이것은 많은 문제가있다 - 우리의 "디 바운서"프로세스를 효과적으로 우리가 디 바운스를 취소 할 수 없습니다, 영원히 살고 신뢰성은 기껏해야 스케치입니다. 우리는 개선 할 수 있지만, 우리는 단지 호출 할 수있는 간단한 재미의 반환 값을 잃어 버릴 것이고, 대신 우리는 우리의 데 바운서를 "적용"하기 위해 특별한 함수를 호출해야 할 것입니다.
defmodule Debounce do
def start(fun, timeout) do
ref = make_ref()
# this function is invoked when we wait for a next application
recur = fn recur, run ->
receive do
{^ref, :run} ->
# let's start counting!
run.(recur, run)
{^ref, :cancel} ->
:cancelled
end
end
# this function is invoked when we "swallow" next applications
# and wait until we finally apply the function
run = fn recur, run ->
receive do
{^ref, :run} ->
# let's reset the counter
run.(recur, run)
{^ref, :cancel} ->
:cancelled
after
timeout ->
# time is up, let's call it for real & return to waiting
fun.()
recur.(recur, run)
end
end
pid = spawn_link(fn -> recur.(recur, run) end)
{pid, ref}
end
def apply({pid, ref}) do
send(pid, {ref, :run})
end
def cancel({pid, ref}) do
send(pid, {ref, :cancel})
end
end
는 다음의 예제를 보자 :
iex> deb = Debounce.start(fn -> IO.puts("Hello"), 5000)
iex> Debounce.apply(deb)
iex> Debounce.apply(deb)
# wait some time
Hello
iex> Debounce.apply(deb)
iex> Debounce.cancel(deb)
# wait some time
# nothing
이 여전히 가능 코너 케이스를 가지고 - 생산 버전은 아마 작업 또는 GenServer을 사용합니다.
내 머리 꼭대기에서 간단한 genserver로 구현할 수 있습니다. 어쩌면 간단한 방법이 있습니다. – JustMichael
그래, 그래,하지만 더 단순한 추상화를 찾고있다 – asiniy
프로세스를 원하는 기능을 원하지 않는다. http://elixir-lang.org/getting-started/processes.html 프로세스가 현재 값을 카운팅하는 동안 루프는 n의 새로운 수신 값을받습니다.이 값은 로컬 상태로 유지되는 목록에 저장됩니다. 각 카운트 다운이 끝나면 목록의 다음 멤버에게 가서 다시 카운트 다운을합니다. – GavinBrelstaff