| import { Observable } from '../Observable'; |
| import { SchedulerLike } from '../types'; |
| import { async as asyncScheduler } from '../scheduler/async'; |
| import { isScheduler } from '../util/isScheduler'; |
| import { isValidDate } from '../util/isDate'; |
| |
| /** |
| * Creates an observable that will wait for a specified time period, or exact date, before |
| * emitting the number 0. |
| * |
| * <span class="informal">Used to emit a notification after a delay.</span> |
| * |
| * This observable is useful for creating delays in code, or racing against other values |
| * for ad-hoc timeouts. |
| * |
| * The `delay` is specified by default in milliseconds, however providing a custom scheduler could |
| * create a different behavior. |
| * |
| * ## Examples |
| * |
| * Wait 3 seconds and start another observable |
| * |
| * You might want to use `timer` to delay subscription to an |
| * observable by a set amount of time. Here we use a timer with |
| * {@link concatMapTo} or {@link concatMap} in order to wait |
| * a few seconds and start a subscription to a source. |
| * |
| * ```ts |
| * import { of, timer, concatMap } from 'rxjs'; |
| * |
| * // This could be any observable |
| * const source = of(1, 2, 3); |
| * |
| * timer(3000) |
| * .pipe(concatMap(() => source)) |
| * .subscribe(console.log); |
| * ``` |
| * |
| * Take all values until the start of the next minute |
| * |
| * Using a `Date` as the trigger for the first emission, you can |
| * do things like wait until midnight to fire an event, or in this case, |
| * wait until a new minute starts (chosen so the example wouldn't take |
| * too long to run) in order to stop watching a stream. Leveraging |
| * {@link takeUntil}. |
| * |
| * ```ts |
| * import { interval, takeUntil, timer } from 'rxjs'; |
| * |
| * // Build a Date object that marks the |
| * // next minute. |
| * const currentDate = new Date(); |
| * const startOfNextMinute = new Date( |
| * currentDate.getFullYear(), |
| * currentDate.getMonth(), |
| * currentDate.getDate(), |
| * currentDate.getHours(), |
| * currentDate.getMinutes() + 1 |
| * ); |
| * |
| * // This could be any observable stream |
| * const source = interval(1000); |
| * |
| * const result = source.pipe( |
| * takeUntil(timer(startOfNextMinute)) |
| * ); |
| * |
| * result.subscribe(console.log); |
| * ``` |
| * |
| * ### Known Limitations |
| * |
| * - The {@link asyncScheduler} uses `setTimeout` which has limitations for how far in the future it can be scheduled. |
| * |
| * - If a `scheduler` is provided that returns a timestamp other than an epoch from `now()`, and |
| * a `Date` object is passed to the `dueTime` argument, the calculation for when the first emission |
| * should occur will be incorrect. In this case, it would be best to do your own calculations |
| * ahead of time, and pass a `number` in as the `dueTime`. |
| * |
| * @param due If a `number`, the amount of time in milliseconds to wait before emitting. |
| * If a `Date`, the exact time at which to emit. |
| * @param scheduler The scheduler to use to schedule the delay. Defaults to {@link asyncScheduler}. |
| */ |
| export function timer(due: number | Date, scheduler?: SchedulerLike): Observable<0>; |
| |
| /** |
| * Creates an observable that starts an interval after a specified delay, emitting incrementing numbers -- starting at `0` -- |
| * on each interval after words. |
| * |
| * The `delay` and `intervalDuration` are specified by default in milliseconds, however providing a custom scheduler could |
| * create a different behavior. |
| * |
| * ## Example |
| * |
| * ### Start an interval that starts right away |
| * |
| * Since {@link interval} waits for the passed delay before starting, |
| * sometimes that's not ideal. You may want to start an interval immediately. |
| * `timer` works well for this. Here we have both side-by-side so you can |
| * see them in comparison. |
| * |
| * Note that this observable will never complete. |
| * |
| * ```ts |
| * import { timer, interval } from 'rxjs'; |
| * |
| * timer(0, 1000).subscribe(n => console.log('timer', n)); |
| * interval(1000).subscribe(n => console.log('interval', n)); |
| * ``` |
| * |
| * ### Known Limitations |
| * |
| * - The {@link asyncScheduler} uses `setTimeout` which has limitations for how far in the future it can be scheduled. |
| * |
| * - If a `scheduler` is provided that returns a timestamp other than an epoch from `now()`, and |
| * a `Date` object is passed to the `dueTime` argument, the calculation for when the first emission |
| * should occur will be incorrect. In this case, it would be best to do your own calculations |
| * ahead of time, and pass a `number` in as the `startDue`. |
| * @param startDue If a `number`, is the time to wait before starting the interval. |
| * If a `Date`, is the exact time at which to start the interval. |
| * @param intervalDuration The delay between each value emitted in the interval. Passing a |
| * negative number here will result in immediate completion after the first value is emitted, as though |
| * no `intervalDuration` was passed at all. |
| * @param scheduler The scheduler to use to schedule the delay. Defaults to {@link asyncScheduler}. |
| */ |
| export function timer(startDue: number | Date, intervalDuration: number, scheduler?: SchedulerLike): Observable<number>; |
| |
| /** |
| * @deprecated The signature allowing `undefined` to be passed for `intervalDuration` will be removed in v8. Use the `timer(dueTime, scheduler?)` signature instead. |
| */ |
| export function timer(dueTime: number | Date, unused: undefined, scheduler?: SchedulerLike): Observable<0>; |
| |
| export function timer( |
| dueTime: number | Date = 0, |
| intervalOrScheduler?: number | SchedulerLike, |
| scheduler: SchedulerLike = asyncScheduler |
| ): Observable<number> { |
| // Since negative intervalDuration is treated as though no |
| // interval was specified at all, we start with a negative number. |
| let intervalDuration = -1; |
| |
| if (intervalOrScheduler != null) { |
| // If we have a second argument, and it's a scheduler, |
| // override the scheduler we had defaulted. Otherwise, |
| // it must be an interval. |
| if (isScheduler(intervalOrScheduler)) { |
| scheduler = intervalOrScheduler; |
| } else { |
| // Note that this *could* be negative, in which case |
| // it's like not passing an intervalDuration at all. |
| intervalDuration = intervalOrScheduler; |
| } |
| } |
| |
| return new Observable((subscriber) => { |
| // If a valid date is passed, calculate how long to wait before |
| // executing the first value... otherwise, if it's a number just schedule |
| // that many milliseconds (or scheduler-specified unit size) in the future. |
| let due = isValidDate(dueTime) ? +dueTime - scheduler!.now() : dueTime; |
| |
| if (due < 0) { |
| // Ensure we don't schedule in the future. |
| due = 0; |
| } |
| |
| // The incrementing value we emit. |
| let n = 0; |
| |
| // Start the timer. |
| return scheduler.schedule(function () { |
| if (!subscriber.closed) { |
| // Emit the next value and increment. |
| subscriber.next(n++); |
| |
| if (0 <= intervalDuration) { |
| // If we have a interval after the initial timer, |
| // reschedule with the period. |
| this.schedule(undefined, intervalDuration); |
| } else { |
| // We didn't have an interval. So just complete. |
| subscriber.complete(); |
| } |
| } |
| }, due); |
| }); |
| } |