|
| 1 | +--- |
| 2 | +id: TimeoutManager |
| 3 | +title: TimeoutManager |
| 4 | +--- |
| 5 | + |
| 6 | +The `TimeoutManager` handles `setTimeout` and `setInterval` timers in TanStack Query. |
| 7 | + |
| 8 | +TanStack Query uses timers to implement features like query `staleTime` and `gcTime`, as well as retries, throttling, and debouncing. |
| 9 | + |
| 10 | +By default, TimeoutManager uses the global `setTimeout` and `setInterval`, but it can be configured to use custom implementations instead. |
| 11 | + |
| 12 | +Its available methods are: |
| 13 | + |
| 14 | +- [`timeoutManager.setTimeoutProvider`](#timeoutmanagersettimeoutprovider) |
| 15 | + - [`TimeoutProvider`](#timeoutprovider) |
| 16 | +- [`timeoutManager.setTimeout`](#timeoutmanagersettimeout) |
| 17 | +- [`timeoutManager.clearTimeout`](#timeoutmanagercleartimeout) |
| 18 | +- [`timeoutManager.setInterval`](#timeoutmanagersetinterval) |
| 19 | +- [`timeoutManager.clearInterval`](#timeoutmanagerclearinterval) |
| 20 | + |
| 21 | +## `timeoutManager.setTimeoutProvider` |
| 22 | + |
| 23 | +`setTimeoutProvider` can be used to set a custom implementation of the `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` functions, called a `TimeoutProvider`. |
| 24 | + |
| 25 | +This may be useful if you notice event loop performance issues with thousands of queries. A custom TimeoutProvider could also support timer delays longer than the global `setTimeout` maximum delay value of about [24 days](https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout#maximum_delay_value). |
| 26 | + |
| 27 | +It is important to call `setTimeoutProvider` before creating a QueryClient or queries, so that the same provider is used consistently for all timers in the application, since different TimeoutProviders cannot cancel each others' timers. |
| 28 | + |
| 29 | +```tsx |
| 30 | +import { timeoutManager, QueryClient } from '@tanstack/react-query' |
| 31 | +import { CustomTimeoutProvider } from './CustomTimeoutProvider' |
| 32 | + |
| 33 | +timeoutManager.setTimeoutProvider(new CustomTimeoutProvider()) |
| 34 | + |
| 35 | +export const queryClient = new QueryClient() |
| 36 | +``` |
| 37 | + |
| 38 | +### `TimeoutProvider` |
| 39 | + |
| 40 | +Timers are very performance sensitive. Short term timers (such as those with delays less than 5 seconds) tend to be latency sensitive, where long-term timers may benefit more from [timer coalescing](https://en.wikipedia.org/wiki/Timer_coalescing) - batching timers with similar deadlines together - using a data structure like a [hierarchical time wheel](https://www.npmjs.com/package/timer-wheel). |
| 41 | + |
| 42 | +The `TimeoutProvider` type requires that implementations handle timer ID objects that can be converted to `number` via [Symbol.toPrimitive][toPrimitive] because runtimes like NodeJS return [objects][nodejs-timeout] from their global `setTimeout` and `setInterval` functions. TimeoutProvider implementations are free to coerce timer IDs to number internally, or to return their own custom object type that implements `{ [Symbol.toPrimitive]: () => number }`. |
| 43 | + |
| 44 | +[nodejs-timeout]: https://nodejs.org/api/timers.html#class-timeout |
| 45 | +[toPrimitive]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive |
| 46 | + |
| 47 | +```tsx |
| 48 | +type ManagedTimerId = number | { [Symbol.toPrimitive]: () => number } |
| 49 | + |
| 50 | +type TimeoutProvider<TTimerId extends ManagedTimerId = ManagedTimerId> = { |
| 51 | + readonly setTimeout: (callback: TimeoutCallback, delay: number) => TTimerId |
| 52 | + readonly clearTimeout: (timeoutId: TTimerId | undefined) => void |
| 53 | + |
| 54 | + readonly setInterval: (callback: TimeoutCallback, delay: number) => TTimerId |
| 55 | + readonly clearInterval: (intervalId: TTimerId | undefined) => void |
| 56 | +} |
| 57 | +``` |
| 58 | +
|
| 59 | +## `timeoutManager.setTimeout` |
| 60 | +
|
| 61 | +`setTimeout(callback, delayMs)` schedules a callback to run after approximately `delay` milliseconds, like the global [setTimeout function](https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout).The callback can be canceled with `timeoutManager.clearTimeout`. |
| 62 | +
|
| 63 | +It returns a timer ID, which may be a number or an object that can be coerced to a number via [Symbol.toPrimitive][toPrimitive]. |
| 64 | +
|
| 65 | +```tsx |
| 66 | +import { timeoutManager } from '@tanstack/react-query' |
| 67 | + |
| 68 | +const timeoutId = timeoutManager.setTimeout( |
| 69 | + () => console.log('ran at:', new Date()), |
| 70 | + 1000, |
| 71 | +) |
| 72 | + |
| 73 | +const timeoutIdNumber: number = Number(timeoutId) |
| 74 | +``` |
| 75 | + |
| 76 | +## `timeoutManager.clearTimeout` |
| 77 | + |
| 78 | +`clearTimeout(timerId)` cancels a timeout callback scheduled with `setTimeout`, like the global [clearTimeout function](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearTimeout). It should be called with a timer ID returned by `timeoutManager.setTimeout`. |
| 79 | + |
| 80 | +```tsx |
| 81 | +import { timeoutManager } from '@tanstack/react-query' |
| 82 | + |
| 83 | +const timeoutId = timeoutManager.setTimeout( |
| 84 | + () => console.log('ran at:', new Date()), |
| 85 | + 1000, |
| 86 | +) |
| 87 | + |
| 88 | +timeoutManager.clearTimeout(timeoutId) |
| 89 | +``` |
| 90 | + |
| 91 | +## `timeoutManager.setInterval` |
| 92 | + |
| 93 | +`setInterval(callback, intervalMs)` schedules a callback to be called approximately every `intervalMs`, like the global [setInterval function](https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval). |
| 94 | + |
| 95 | +Like `setTimeout`, it returns a timer ID, which may be a number or an object that can be coerced to a number via [Symbol.toPrimitive](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive). |
| 96 | + |
| 97 | +```tsx |
| 98 | +import { timeoutManager } from '@tanstack/react-query' |
| 99 | + |
| 100 | +const intervalId = timeoutManager.setInterval( |
| 101 | + () => console.log('ran at:', new Date()), |
| 102 | + 1000, |
| 103 | +) |
| 104 | +``` |
| 105 | + |
| 106 | +## `timeoutManager.clearInterval` |
| 107 | + |
| 108 | +`clearInterval(intervalId)` can be used to cancel an interval, like the global [clearInterval function](https://developer.mozilla.org/en-US/docs/Web/API/Window/clearInterval). It should be called with an interval ID returned by `timeoutManager.setInterval`. |
| 109 | + |
| 110 | +```tsx |
| 111 | +import { timeoutManager } from '@tanstack/react-query' |
| 112 | + |
| 113 | +const intervalId = timeoutManager.setInterval( |
| 114 | + () => console.log('ran at:', new Date()), |
| 115 | + 1000, |
| 116 | +) |
| 117 | + |
| 118 | +timeoutManager.clearInterval(intervalId) |
| 119 | +``` |
0 commit comments