|
451 | 451 | " \"\"\" Decorator that prevents a function from being called\n",
|
452 | 452 | " more than once every wait period. \"\"\"\n",
|
453 | 453 | " def decorator(fn):\n",
|
454 |
| - " time_of_last_call = time()\n", |
455 |
| - " first_time = True\n", |
| 454 | + " time_of_last_call = 0\n", |
| 455 | + " scheduled = False\n", |
| 456 | + " new_args, new_kwargs = None, None\n", |
456 | 457 | " def throttled(*args, **kwargs):\n",
|
| 458 | + " nonlocal new_args, new_kwargs, time_of_last_call, scheduled\n", |
457 | 459 | " def call_it():\n",
|
458 |
| - " fn(*args, **kwargs)\n", |
459 |
| - " try:\n", |
460 |
| - " throttled.t.cancel()\n", |
461 |
| - " except(AttributeError):\n", |
462 |
| - " pass\n", |
463 |
| - " throttled.t = Timer(wait, call_it)\n", |
464 |
| - " nonlocal time_of_last_call, first_time\n", |
465 |
| - " now = time()\n", |
466 |
| - " if first_time or (now - time_of_last_call > wait):\n", |
467 |
| - " first_time = False\n", |
468 |
| - " time_of_last_call = now\n", |
469 |
| - " return fn(*args, **kwargs)\n", |
| 460 | + " nonlocal new_args, new_kwargs, time_of_last_call, scheduled\n", |
| 461 | + " time_of_last_call = time()\n", |
| 462 | + " fn(*new_args, **new_kwargs)\n", |
| 463 | + " scheduled = False\n", |
| 464 | + " time_since_last_call = time() - time_of_last_call\n", |
| 465 | + " new_args = args\n", |
| 466 | + " new_kwargs = kwargs\n", |
| 467 | + " if not scheduled:\n", |
| 468 | + " new_wait = max(0, wait - time_since_last_call)\n", |
| 469 | + " Timer(new_wait, call_it)\n", |
| 470 | + " scheduled = True\n", |
470 | 471 | " return throttled\n",
|
471 | 472 | " return decorator"
|
472 | 473 | ]
|
|
475 | 476 | "cell_type": "markdown",
|
476 | 477 | "metadata": {},
|
477 | 478 | "source": [
|
478 |
| - "To see how different it behaves compared to the debouncer, you can decorate the `value_changed` function above with `throttle(0.2)` instead of `debounce(0.2)`. Note that both decorators should not be used together." |
| 479 | + "To see how different it behaves compared to the debouncer, here is the same slider example, with its throttled value displayed in the text box. Notice how more interactive it is, while still limiting the callback rate." |
| 480 | + ] |
| 481 | + }, |
| 482 | + { |
| 483 | + "cell_type": "code", |
| 484 | + "execution_count": null, |
| 485 | + "metadata": {}, |
| 486 | + "outputs": [], |
| 487 | + "source": [ |
| 488 | + "slider = widgets.IntSlider()\n", |
| 489 | + "text = widgets.IntText()\n", |
| 490 | + "\n", |
| 491 | + "@throttle(0.2)\n", |
| 492 | + "def value_changed(change):\n", |
| 493 | + " text.value = change.new\n", |
| 494 | + "slider.observe(value_changed, 'value')\n", |
| 495 | + "\n", |
| 496 | + "widgets.VBox([slider, text])" |
479 | 497 | ]
|
480 | 498 | },
|
481 | 499 | {
|
|
0 commit comments