In RxJS, how do interval(5000), timer(5000) and timer(0, 5000) differ, and which suits polling that must fire immediately?
answer
- when is the first value
- does it ever complete
- timer(dueTime, period)
- a counter starting at 0
basics
~20 sinterval(5000) emits 0, 1, 2... every 5 s, first after 5 s, forever. timer(5000) emits 0 once after 5 s and completes. timer(0, 5000) emits at once, asynchronously, then every 5 s - the usual choice for polling.
solid answer
~40 sAll three emit an incrementing counter starting at `0` on RxJS's async scheduler. `interval(period)` is implemented as `timer(period, period)`: its first value arrives only after one full period, and it never completes. `timer(dueTime)` waits once, emits `0`, and **completes** - a delayed one-shot. `timer(dueTime, period)` waits `dueTime`, then emits every `period` without completing, so `timer(0, 5000)` fires on the next tick and then every five seconds. For polling that must show data straight away, `timer(0, period)` is the right source; `interval` would leave the screen empty for the first period. `timer` also accepts a `Date` as `dueTime` to fire at an absolute time. Even `timer(0)` is asynchronous: its value arrives after the `subscribe()` call returns.
code
ts · 14 linesimport { switchMap, takeWhile, timer } from 'rxjs';
import { ajax } from 'rxjs/ajax';
interface JobStatus {
state: 'queued' | 'running' | 'done' | 'failed';
}
const jobStatus$ = timer(0, 5000).pipe(
switchMap(() => ajax.getJSON<JobStatus>('/api/jobs/42')),
takeWhile((s) => s.state === 'queued' || s.state === 'running', true),
);
const sub = jobStatus$.subscribe((s) => console.log('status', s.state));
console.log('subscribed'); // printed before the first status: timer(0) is asynchronousgo deeper
Recall the three shapes: interval waits a full period first, one-argument timer fires once and completes, two-argument timer sets its own first delay.
Explain that interval is timer(period, period), that timer(0) is still asynchronous, and why timer(0, period) is the polling source.
Show how polling ends: unsubscribe, take or takeWhile on a final state, and what leaks when a periodic source outlives its screen.
Weigh client polling intervals against server load and push alternatives, and set a team default for how polling streams are started and stopped.
## Three time-based sources RxJS has two creation functions for time: **`interval`** and **`timer`**. Both emit an **incrementing number starting at `0`** and both schedule their work on RxJS's `asyncScheduler` by default, which uses the platform's timers. They differ in when the first value arrives and whether the stream ends. | Call | First value | Later values | Completes | |---|---|---|---| | `interval(5000)` | `0` after 5 s | `1`, `2`, ... every 5 s | never | | `timer(5000)` | `0` after 5 s | none | yes, right after `0` | | `timer(0, 5000)` | `0` on the next timer tick | `1`, `2`, ... every 5 s | never | | `timer(date)` | `0` at that `Date` | none | yes | In RxJS 7's source, `interval(period)` is literally `timer(period, period)`, so `interval` is just the special case of `timer` where the first delay equals the period. ## timer with one argument: a delayed one-shot `timer(dueTime)` emits a single `0` after `dueTime` milliseconds - or at a given `Date` - and then **completes**. It is the RxJS equivalent of `setTimeout` that can be cancelled by unsubscribing and composed with operators. A `Date` in the past, or a negative number, is treated as zero. ## timer with two arguments: a periodic source with a chosen start `timer(dueTime, period)` waits `dueTime`, emits `0`, then emits every `period`. It never completes. Passing `0` as `dueTime` is the standard way to say "now, and then every N milliseconds". Even with `dueTime` of `0`, the first value is **asynchronous**: it is scheduled on a timer, so it arrives after `subscribe()` returns and after the current synchronous code has run. Code that expects the first poll result on the line after `subscribe()` will not see it. ## The polling scenario A dashboard polls a job-status endpoint every five seconds and must show the status as soon as it opens. - With `interval(5000)`, the first request goes out only after five seconds, so the screen stays empty. - With `timer(0, 5000)`, the first request goes out immediately and then every five seconds. - `timer(5000)` is wrong here - it fires once and completes. Each tick is mapped to a request with a flattening operator; which one to choose - so that a slow response is not overtaken or duplicated - is a separate topic. ## Ending a periodic source `interval` and two-argument `timer` never complete, so the polling runs until something stops it: 1. the consumer **unsubscribes**, which cancels the scheduled timer through the subscription's teardown; 2. an operator such as `take(n)` or `takeWhile(...)` ends it after enough ticks or when the job reaches a final state; 3. an error in the pipeline ends it, unless it is recovered upstream. Forgetting this is the classic polling leak: requests keep going out after the screen that needed them is gone. ## Choosing the right call - One delayed action, such as hiding a toast after three seconds: `timer(3000)`. - A repeating action whose first run should wait one period, such as an autosave: `interval(period)`. - A repeating action that must run now and then repeatedly, such as polling: `timer(0, period)`. - An action at a wall-clock moment: `timer(someDate)`. ## Details worth knowing - The emitted value is the **tick index**, not a timestamp. If you need time, map to `Date.now()` or use a timestamping operator. - A negative `period` passed to `interval` is treated as `0`. - Both functions accept a scheduler as the last argument. For these time-based functions it is **not** deprecated - it is how marble tests substitute virtual time - unlike the scheduler argument on `of` and `from`. - `range(start, count)` is sometimes confused with them: it is a **synchronous** counter with no timing at all, emitting `count` numbers from `start` and completing. With one argument, `range(5)` emits `0` to `4`. ## What interviewers listen for The first-emission difference between `interval` and `timer(0, period)`, the fact that one-argument `timer` completes, and the awareness that neither periodic source ends by itself.
- In RxJS, is interval(0) or timer(0) synchronous?No. Both schedule on `asyncScheduler`, which uses platform timers, so the first value arrives after `subscribe()` returns and after the current synchronous code. A zero delay only means "as soon as the timer fires". If you need a value delivered synchronously on subscribe, `of(0)` does that.
- In RxJS, how do you stop a timer(0, 5000) polling stream when the job reaches a final state?Add a completing operator after the request, such as `takeWhile(s => !isFinal(s), true)`. The `true` inclusive flag emits the final status before completing, and completion unsubscribes from the timer, so no further requests are sent. Unsubscribing from the outside also stops it.
saying these in an interview costs you the question
- interval(5000) emits its first value immediately on subscribe.
- timer(5000) keeps emitting every five seconds.
- timer(0, 5000) delivers its first value synchronously inside subscribe().
- interval stops by itself once nobody reads its values.
- interval and timer emit the current timestamp rather than a counter.