Skip to content

Commit 46dce1d

Browse files
feat($common): refine @debounce and @Throttle decorators
1 parent 5a4d11b commit 46dce1d

1 file changed

Lines changed: 42 additions & 42 deletions

File tree

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,75 @@
1-
import asyncio
1+
from threading import Timer
22
from time import time
33

4+
from loguru import logger
45

5-
class Setter:
6-
def __init__(self, initial_value=None) -> None:
7-
self._value = initial_value
8-
9-
def get(self):
10-
return self._value
116

12-
def set(self, v):
13-
self._value = v
14-
15-
16-
def debounce(delay):
7+
def debounce(interval: float):
178
"""
18-
Debounce decorator.
9+
Decorator that will postpone a functions
10+
execution until after wait seconds
11+
have elapsed since the last time it was invoked.
1912
20-
@see Python 中的防抖与节流 https://www.bilibili.com/read/cv13257868
13+
@param interval: interval time in seconds
14+
@see https://gist.github.com/walkermatt/2871026
2115
"""
2216

23-
# 用于存储 asyncio.Task 实例,这里是闭包
24-
task = Setter()
25-
2617
def decorator(fn):
27-
# Task 协程函数
28-
async def f(*args, **kwargs):
29-
# 进行休眠
30-
await asyncio.sleep(delay)
31-
# 调用函数
32-
f1 = fn(*args, **kwargs)
33-
# 支持回调函数是异步函数的情况
34-
if asyncio.iscoroutine(f1):
35-
await f1
36-
# 清除 task
37-
task.set(None)
38-
39-
def wrapper(*args, **kwargs):
40-
# 如果 task 存在,说明在 delay 秒内调用过一次函数,此次调用应当重置计时器,因此取消先前的 Task
41-
if task.get() is not None:
42-
task.get().cancel()
43-
# 创建 Task 并赋值变量 task
44-
task.set(asyncio.create_task(f(*args, **kwargs)))
45-
46-
return wrapper
18+
def debounced(*args, **kwargs):
19+
def call_it():
20+
fn(*args, **kwargs)
21+
logger.debug(f"Called debounced function: {fn}")
22+
23+
try:
24+
debounced.t.cancel()
25+
logger.debug(f"Cancelled calling debounced function: {fn}")
26+
except AttributeError:
27+
pass
28+
debounced.t = Timer(interval, call_it)
29+
debounced.t.start()
30+
31+
return debounced
4732

4833
return decorator
4934

5035

51-
def throttle(delay):
36+
class Wrapper:
37+
def __init__(self, initial_value=None) -> None:
38+
self._value = initial_value
39+
40+
def get(self):
41+
return self._value
42+
43+
def set(self, v):
44+
self._value = v
45+
46+
47+
def throttle(interval: float):
5248
"""
5349
Throttle decorator.
5450
51+
@param interval: interval time in seconds
52+
@see Python 中的防抖与节流 https://www.bilibili.com/read/cv13257868/
5553
@see Python 中的防抖与节流 https://www.moyu.moe/articles/25/
5654
"""
5755

5856
# 下一次许可调用的时间,初始化为 0
59-
next_t = Setter(0)
57+
next_t = Wrapper(0)
6058

6159
def decorator(fn):
62-
def wrapper(*args, **kwargs):
60+
def throttled(*args, **kwargs):
6361
# 当前时间
6462
now = time()
6563
# 若未到下一次许可调用的时间,直接返回
6664
if next_t.get() > now:
65+
logger.debug(f"Skipped throttled call, function: {fn}")
6766
return
6867
# 更新下一次许可调用的时间
69-
next_t.set(now + delay)
68+
next_t.set(now + interval)
7069
# 调用函数并返回
70+
logger.debug(f"Called throttled function: {fn}")
7171
return fn(*args, **kwargs)
7272

73-
return wrapper
73+
return throttled
7474

7575
return decorator

0 commit comments

Comments
 (0)