npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

rxjs-poll

v2.0.10

Published

A flexible RxJS operator library that enables polling on any completed observable source with advanced timing and retry strategies

Readme

RxJS Polling Operator

A flexible RxJS operator library that enables polling on any completed observable source with advanced timing and retry strategies.

🚀 Features

  • Two polling types: repeat and interval to suit different use cases
  • Timing strategies: constant, linear, exponential, random and dynamic (custom logic)
  • Auto-pause: Automatically pause/resume polling based on page visibility (browser only)
  • Flexible retries: Control retry attempts with consecutive or total counting modes
  • Input validation: Guards against unexpected input time values
  • Cross-platform: Works in both browser and Node.js environments
  • Modern compatibility: Compatible with RxJS v7+
  • Multiple module formats: Supports CJS, ESM, and UMD

📦 Installation

npm install rxjs-poll --save

🎯 Purpose & Process

Polling is essential when you need to repeatedly check for updates from sources that don't provide real-time notifications. Common scenarios include monitoring HTTP API endpoints for status changes, watching DOM elements for state updates, or periodically sampling data streams.

This operator cleanly separates polling concerns from your core observable logic. It waits for your source observable to complete per polling type, then schedules the next poll based on your configuration. The architecture distinguishes between normal polling delays and error retry scenarios, giving you precise control over both success and failure timing strategies.

📚 Usage Examples

Default Configuration

▶️ Live Demo

Plug and play - just add the operator to your pipe and start polling.

import { poll } from 'rxjs-poll';
import { takeWhile } from 'rxjs';

request$
  .pipe(
    poll(), // Poll every second with exponential retry strategy (7s max)
    takeWhile(({ status }) => status !== 'done', true)
  )
  .subscribe({ next: console.log });

Strategy-Based Configuration

▶️ Live Demo

Use built-in strategies for easy timing control.

import { poll } from 'rxjs-poll';
import { takeWhile } from 'rxjs';

request$
  .pipe(
    poll({
      type: 'interval', // Drops uncompleted source after delay
      delay: {
        strategy: 'random',
        time: [1000, 3000], // Random delay between 1 and 3 seconds
      },
      retry: {
        limit: Infinity, // Will never throw
      },
    }),
    takeWhile(({ status }) => status !== 'done', true)
  )
  .subscribe({ next: console.log });

Advanced Dynamic Strategies

▶️ Live Demo

Implement complex polling strategies with dynamic timing based on poll state.

import { poll } from 'rxjs-poll';
import { takeWhile } from 'rxjs';

request$
  .pipe(
    poll({
      delay: {
        /** Adaptive polling based on response data */
        strategy: 'dynamic',
        time: ({ value }) => (value?.items.length ? 1000 : 500),
      },
      retry: {
        /** Custom exponential backoff with jitter */
        strategy: 'dynamic',
        time: ({ consecutiveRetryCount }) => {
          const exponential = Math.pow(2, consecutiveRetryCount - 1) * 1000;
          const jitter = Math.random() * 200;

          return exponential + jitter;
        },
        limit: 6,
      },
    }),
    takeWhile(({ status }) => status !== 'done', true)
  )
  .subscribe({ next: console.log });

📋 API Reference

poll(config?: PollConfig)

Creates a polling operator that will begin polling once the source observable completes.

PollConfig

interface PollConfig {
  /**
   * Defines the polling behavior:
   * - 'repeat': Polls after current source completes
   * - 'interval': Polls in intervals, dropping any ongoing source operations
   * @default 'repeat'
   */
  type?: 'repeat' | 'interval';

  /**
   * Configuration for polling delays (between successful operations)
   */
  delay?: {
    /**
     * Strategy type for delay timing. Built-in strategies (except dynamic)
     * calculate time per state's `pollCount`.
     * @default 'constant'
     */
    strategy: 'constant' | 'random' | 'dynamic';

    /**
     * Time (ms) depending on strategy:
     * - constant: number
     * - random: [min, max]
     * - dynamic: (state) => number | [min, max]
     * @default 1000
     */
    time:
      | number
      | [min: number, max: number]
      | (state: PollState) => number | [min: number, max: number];
  };

  /**
   * Configuration for retry behavior (on errors).
   * Can be fully specified with strategy/time, or partially specified with just limit/consecutiveOnly.
   * If omitted entirely, uses default exponential retry strategy.
   * - Full config: `{ strategy: '...', time: ..., limit?: ..., consecutiveOnly?: ... }`
   * - Partial config: `{ limit: ..., consecutiveOnly?: ... }` (uses default strategy/time)
   * - Omit entirely: Uses all defaults
   */
  retry?: {
    /**
     * Strategy type for retry timing. Built-in strategies (except dynamic)
     * calculate time per state:
     * - consecutiveOnly: true → uses `consecutiveRetryCount`
     * - consecutiveOnly: false → uses `retryCount`
     * @default 'exponential'
     * @note Required if `time` is provided, otherwise omitted to use defaults
     */
    strategy: 'constant' | 'linear' | 'exponential' | 'random' | 'dynamic';

    /**
     * Time (ms) depending on strategy:
     * - constant: number
     * - linear: number
     * - exponential: number
     * - random: [min, max]
     * - dynamic: (state) => number | [min, max]
     * @default 1000
     * @note Required if `strategy` is provided, otherwise omitted to use defaults
     */
    time:
      | number
      | [min: number, max: number]
      | (state: PollState) => number | [min: number, max: number];

    /**
     * Maximum number of retry attempts before throwing an error.
     * Use `Infinity` to keep retrying indefinitely.
     * @default 3
     */
    limit?: number;

    /**
     * Controls how retries are counted:
     * - true: Only consecutive errors count toward retry limit
     *   (resets counter on success)
     * - false: All errors count toward retry limit regardless of
     *   successful responses between them
     * @default true
     */
    consecutiveOnly?: boolean;
  };

  /**
   * [Browser only] Controls polling behavior when page isn't visible
   * - true: Pause polling when tab isn't active, and resume on active
   * - false: Poll even when tab isn't focused
   * @default true
   */
  pauseWhenHidden?: boolean;
}

PollState

State object passed to delay/retry time producer functions:

interface PollState<T> {
  /** Latest value from the source. For `interval` polling type,
   * first emission is undefined. */
  value: T | undefined;

  /** Latest error when retrying */
  error: any | undefined;

  /** Total number of successful poll operations */
  pollCount: number;

  /** Total number of retry attempts */
  retryCount: number;

  /** Current number of consecutive retry attempts */
  consecutiveRetryCount: number;
}

/** Note: pollCount + retryCount = total attempts */

🚨 Breaking Changes

Version 2 (source) introduces an API focused on strategy-based configuration with improved type safety and clearer separation between polling delays and retry behavior. See V2 Changes for detailed migration guide and examples.

Version 1 (source) will continue to receive bug fixes and security updates.

🤝 Contributing

Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.

Have a question? Check out GitHub Discussions to ask questions, share ideas, or get help from the community.

🙌 Credits

This library is inspired by rx-polling, which creates an Observable for polling.

📄 License

MIT