Eric Grunzke
Eric Grunzke

Reputation: 1657

Rate limit function calls in Typescript

Update: I now know that throttle will drop excess function invocations, so it is not the correct tool. I'd still like an idiomatic way to process all items in a queue without going too quickly or dropping any items.


I'm writing a node app that hits an API with a rate limit. I can create calls much faster than I'm allowed to send them. I'd like to consume a queue of calls, but without going too quickly or dropping any of them. I made a small typscript test to illustrate my trouble:

import * as _ from "lodash";

let start = new Date().getTime();

function doLog(s: string) {
  let elapsed = new Date().getTime() - start;
  console.log(`${s} ${elapsed}`);
}

let array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
let throttled = _.throttle(doLog, 100);
array.forEach(s => throttled(s));

I expected to see output roughly like:

a 2
b 101
c 203
d 302
e 405
f 502
g 603
h 706
i 804
j 902

But instead I see:

a 2
j 101

Some odd observations I've made:

Upvotes: 2

Views: 5183

Answers (3)

fregante
fregante

Reputation: 31698

If you don't care about doLog() being safely "done" before calling the next one, you can just use setTimeout

let array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
array.forEach((s, i) => setTimeout(doLog, i*100, s));

Adam gives a good explanation as to why throttle isn't good in this case.

Upvotes: 3

Ptival
Ptival

Reputation: 9437

If you'd be willing to use RxJS, this answer would let you achieve this fairly idiomatically:

https://stackoverflow.com/a/31855054/553003

Upvotes: 0

Adam Boduch
Adam Boduch

Reputation: 11211

If a throttled function is called more than once during it's wait period, subsequent calls are ignored. If you need to process every item in an array, throttle() probably isn't what you want. It's better suited for preventing excessive updates in the UI, for example.

The reason you're always seeing a and j in your output is because of leading and trailing edges. The whole array was processed in less than 100ms, but since the leading and trailing default to true, you're seeing both of these calls (the first and the last call to the throttled function).

Upvotes: 3

Related Questions