> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/web/js/val/func/kind/higher/decorator/throttle-f-s.md).

# throttle(f, s)

throttle function calls by every s seconds.

[JS](/web/js.md) ⟩ [technique](/web/js/tech.md) ⟩ [decorator](/web/js/val/func/kind/higher/decorator.md) ⟩ :floppy\_disk: throttle(f, s)

{% hint style="success" %}
([decorator](/web/js/val/func/kind/higher/decorator.md)) <mark style="color:yellow;">**throttle**</mark> function calls by <mark style="color:yellow;">**every**</mark>**&#x20;**<mark style="color:blue;">**s**</mark>**&#x20;**<mark style="color:yellow;">**seconds**</mark>.
{% endhint %}

{% tabs %}
{% tab title="🗺️ 圖解" %} <img src="https://2527454625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MfvEFZnSBhKT6fJmus0%2Fuploads%2F6uBdzRHIbQiT5mzkuLOv%2Fthrottle.timeline.svg?alt=media&amp;token=dd9f9dec-2230-435c-8ce6-085ee838429b" alt="throttle: timeline/state view" class="gitbook-drawing">

<img src="https://2527454625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MfvEFZnSBhKT6fJmus0%2Fuploads%2FrmFQ1sBVTAyE3jTanSY2%2Fthrottle.timer.view.svg?alt=media&amp;token=b6c049cd-9c50-417e-bb8a-42d089473be2" alt="throttle: timer view" class="gitbook-drawing">
{% endtab %}

{% tab title="💾 程式" %}

* replit：[throttle(f, s)](https://replit.com/@pegasusroe/decorator-throttlef#throttle.js)
* [🗺️ 圖解](#tu-jie)

```javascript
// 📁 throttle.js
const { log } = console;

// ⭐️ decorator: "throttle"
//   (throttle function calls by every s seconds)
function throttle(f, s) {

    // log
    log(`'${f.name}' has been throttled by every ${s} seconds.`);

    // ⭐️ throttler's states
    let inCooldownMode = false;    // ⭐️ in "cooldown" mode
    let savedCall;                 // ⭐️ saved call

    // ⭐️ throttler ("wrapper")
    return function wrapper(...args) {

        // 🔸 case 1: in "cooldown" mode
        // ---------------------------------------
        // ④ save call (without executing/forwarding it)
        
        if (inCooldownMode) {
            savedCall = { arguments: args, context: this };    // ④ 
            return;
        }

        // 🔸 case 2: in "idle"/"cool" mode
        // ---------------------------------------
        // ① switch to "cooldown" mode
        // ② forword call to `f`
        // ③ set timer (switch back to "idle" mode in `s` seconds)

        inCooldownMode = true;     // ①
        f.apply(this, args);       // ②

        // ③
        setTimeout(() => {
            
            // time's up!
            // ------------------------------------
            // ⑤ switch back to "idle" mode
            // ⑥ check saved call:
            //
            //    • case 1: there's a saved call
            //      ----------------------------
            //          ⑦ send saved call
            //          ⑧ clear saved call
            //
            //    • case 2: no saved call 
            //      ----------------------
            //           (do nothing)
            //
            // ------------------------------------
            
            inCooldownMode = false;        // ⑤ switch back to "idle" mode
            
            if (savedCall) {               // ⑥ check saved call
                
                // case 1: there's a saved call
                
                // ⑦ send saved call
                //   (⭐️ "saved call" sent to "wrapper", not `f`❗)
                wrapper.apply(savedCall.context, savedCall.arguments);
                savedCall = null;          // ⑧ clear saved call
                
            }   // case 2: no saved call (do nothing)
            
        }, s * 1000);        // timer turned off in `s` seconds
    }

}

// export
module.exports = { throttle }
```

{% endtab %}

{% tab title="💈範例" %}

* replit：[throttle(f, s)](https://replit.com/@pegasusroe/decorator-throttlef#index.js)

```javascript
// 📁 index.js
const { log } = console;
const { throttle } = require('./throttle.js');

// object
let user = {
    // property
    name: 'Joe',
    // method
    say(...args) { 
        const t = Date.now();            // current time
        const T = (t - t0)/1000;         // time elapsed in seconds
        log(T.toFixed(2), `${this.name}: '${args}'`); 
    }
};

// passes calls to `user.say` at maximum once per 1000 ms
user.say = throttle(user.say, 1);

// send message
function send(msg, sec) {
    setTimeout(() => user.say(msg), sec * 1000)
}

const t0 = Date.now();

send('a', 0.5); 
send('b', 1.2);
send('c', 2);
send('d', 2.5);
send('e', 4);
send('d', 4.5);

//      ✅        ✅   ❌   ✅            ✅        ✅ 
//       a         b         d              e         f  <---- forwarded calls
//                 |<──CDM──>|                        |<──CDM──>|
//       |<──CDM──>|         |<──CDM──>|    |<──CDM──>|
//      (a)    [b]     [c]  [d]            (e)  [f]
//  |....╷....|....╷....|....╷....|....╷....|....╷....|....╷....|
//  0         1         2         3         4         5         6 sec
//
// CDM: "cooldown" mode
// (a): send call (a)
// [b]: save call (b)
//  d : forworded call

// log
// --------------------
// 'say' has been throttled by every 1 seconds.
//
// 0.50 Joe: 'a'
// 1.50 Joe: 'b'
// 2.50 Joe: 'd'
// 4.00 Joe: 'e'
// 5.00 Joe: 'd'
```

{% endtab %}

{% tab title="👥 相關" %}

* [decorator](/web/js/val/func/kind/higher/decorator.md)
* compare： [debounce vs. throttle](/web/js/val/func/kind/higher/decorator/debounce-vs.-throttle.md)
  {% endtab %}

{% tab title="📘 手冊" %}

* [ ] [clearTimeout()](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout)
* [ ] [setTimeout()](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout)
* [ ] [Date.now()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now) - number of milliseconds elapsed since 1970/1/1 (00:00:00 UTC).
  {% endtab %}

{% tab title="📗 參考" %}

* [x] JS.info ⟩ [Decorators and forwarding, call/apply](https://javascript.info/call-apply-decorators) ⭐️
* [ ] [YDKJS: Scope & Closures (v.2)](/web/master/ref/book/you-dont-know-js-series-v.2/ydkjs-scope-and-closures-v.2.md) ⟩ Ch. 6  (by IIFE, ie. closure)
* [ ] [\[演算法\] Fibonacci：善用 cache 和 Memoization 提升程式效能](https://pjchender.blogspot.com/2017/09/fibonacci-cache-memoization.html) (by parameter)
* [ ] Wictionary ⟩  [memoize](https://en.wiktionary.org/wiki/memoize)&#x20;
  {% endtab %}
  {% endtabs %}
