简体   繁体   中英

How can I limit the call with throttle even after the window?

I want to limit the call of function not more than once in 3s. but hope it can be invoked at first and delay all others after the wait. My use case is, limit the sending requests and then batch all on in the waiting to third party services. but not for the first call, it's a pain to wait for the first call.

so I made a throttle with lodash like this

const maxThrottle = _.throttle(() => console.log(new Date()), 3000, { trailing: true, leading: true })

and the calls are:

console.log('start: ', new Date())
maxThrottle()
await setTimeout(100)
maxThrottle()
await setTimeout(3000)
maxThrottle()

what I expected:

start:  2022-09-04T06:58:01.099Z
2022-09-04T06:58:01.100Z
2022-09-04T06:58:04.104Z
2022-09-04T06:58:07.104Z

actual:

start:  2022-09-04T06:58:01.099Z
2022-09-04T06:58:01.100Z
2022-09-04T06:58:04.104Z
2022-09-04T06:58:04.214Z  // it is violating the speed of service which I want to avoid.

how can I do it with throttle? is it possible?

I can achieve the behavior with this code:

function limitSpeed(fn: () => void, wait: number) {
  let calledAt: number | null
  let promise: Promise<void> | null
  return () => {
    const timeLeft = calledAt ? wait - (Date.now() - calledAt) : 0
    if (promise)
      return

    if (timeLeft <= 0) {
      calledAt = Date.now()
      fn()
    } else {
      promise = setTimeout(timeLeft).then(() => {
        calledAt = Date.now()
        fn()
        promise = null
      })
    }
  }
}

const maxThrottle = limitSpeed(() => console.log(new Date()), 3000)
console.log('start: ', new Date())
maxThrottle()
await setTimeout(100)
maxThrottle()
await setTimeout(3000)
maxThrottle()

while(true) {
  maxThrottle()
  await setImmediate()
}

result:

start:  2022-09-04T07:22:13.621Z
2022-09-04T07:22:13.622Z
2022-09-04T07:22:16.630Z
2022-09-04T07:22:19.629Z
2022-09-04T07:22:22.628Z
2022-09-04T07:22:25.627Z
2022-09-04T07:22:28.626Z
2022-09-04T07:22:31.625Z
2022-09-04T07:22:34.624Z
2022-09-04T07:22:37.623Z
2022-09-04T07:22:40.622Z
2022-09-04T07:22:43.621Z
2022-09-04T07:22:46.621Z
2022-09-04T07:22:49.620Z
2022-09-04T07:22:52.619Z
2022-09-04T07:22:55.618Z
2022-09-04T07:22:58.617Z
2022-09-04T07:23:01.616Z
2022-09-04T07:23:04.615Z
2022-09-04T07:23:07.614Z
2022-09-04T07:23:10.613Z
2022-09-04T07:23:13.613Z
2022-09-04T07:23:16.613Z
2022-09-04T07:23:19.613Z
2022-09-04T07:23:22.613Z
2022-09-04T07:23:25.613Z
2022-09-04T07:23:28.613Z
2022-09-04T07:23:31.613Z
2022-09-04T07:23:34.613Z
2022-09-04T07:23:37.613Z
2022-09-04T07:23:40.613Z

It seems it is a bug of lodash . It is working perfect with underscore . After replacement of underscore , the problem has gone. I guess lodash doesn't handle the case of throttle after the trailing. It will trigger immediately without wait with leading=true .

As of Sep 2022, lodash is no longer maintaining for two years. So I prefer switching to underscore if you have the same issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM