-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Performance issue in @tanstack/query-async-storage-persister (and possibly #updateStaleTimeout) #6489
Comments
if you have a better implementation that is also correct, please do contribute 🙏. The Maybe we can also get inspired by other, already existing implementations? |
@Jack-Works would you consider contributing your patch back to the persister plugin? |
Hi! I think our patch is obviously imperfect (it is over simplified and maybe even incorrect). I hope your team can find another throttle implementation and I'd like to try it. |
@TkDodo Genuine question: why don't you use p-throttle? :) I'm just trying to understand what makes |
Hello @jhnns, I was also wondering why not just use Take the following example: const start = performance.now();
const fn = (a, b) => {
const time = Math.floor(performance.now() - start);
const result = a + b;
console.log({ time, result });
};
const throttledFn = asyncThrottle(fn, { interval: 500 });
throttledFn(1, 2); // prints: { time: 0, result: 3 }
throttledFn(1, 3); // ignored
throttledFn(1, 4); // ignored
throttledFn(1, 5); // ignored
throttledFn(1, 6); // prints: { time: 500, result: 7 } So to my understanding, While import pThrottle from "p-throttle";
const start = performance.now();
const fn = (a, b) => {
const time = Math.floor(performance.now() - start);
const result = a + b;
console.log({ time, result });
};
const throttle = pThrottle({
limit: 1,
interval: 500,
});
const throttledFn = throttle(fn, { interval: 500 });
throttledFn(1, 2); // prints: { time: 0, result: 3 }
throttledFn(1, 3); // prints: { time: 500, result: 4 }
throttledFn(1, 4); // prints: { time: 1000, result: 5 }
throttledFn(1, 5); // prints: { time: 1500, result: 6 }
throttledFn(1, 6); // prints: { time: 2000, result: 7 } I didn't find a way to tell |
@Jack-Works I made the PR #7224 that suggests a new implementation. Can you please try it on your project and let us know if it fixes the issue? |
Describe the bug
It looks like delayFunc in the
packages/query-async-storage-persister/src/asyncThrottle.ts
has some performance problem.this is the 4x slow-down profile, each
refetch
call causespersistQueryClientSave
to be called, and thendelayFunc
is the slowest function in the tree. All small yellow bars aresetTimeout
orclearTimeout
calls.My throttle timeout is the default (1e3), therefore it cannot be caused by
execFunc
(all thosedelayFunc
calls happen within 1 second).I try to patch my node_modules and replace the
asyncThrottle
with this:This implementation is incorrect but fast.
After the patch,
persistQueryClientSave
now only costs 1 ms instead of 57 ms.I think it looks like calling
setTimeout
orclearTimeout
is costly. I think a better async throttle implementation can avoid calling them so often.btw I also observed that
#updateStaleTimeout
method has a similar behavior.also, this method behaves like
delayFunc
, simple but costs a lot of time (cancel & create timer).Your minimal, reproducible example
n/a
Steps to reproduce
Sorry I didn't provide one, but my patch works so I think my analysis of the performance problem is correct.
I'm happy to try any new asyncThrottle implementation (by patch node_modules, so maintainers don't have to release a new version for this) in our project to see if that fixes the performance problem. Thanks!
Expected behavior
No performance problem
How often does this bug happen?
Every time
Screenshots or Videos
No response
Platform
Chrome 119
@tanstack/query-async-storage-persister 5.8.7
Tanstack Query adapter
None
TanStack Query version
5.8.7
TypeScript version
No response
Additional context
No response
The text was updated successfully, but these errors were encountered: