@avalane/rxjs-spy

中文文档
8.0.4发布于 2025/08/16MITTypeScriptESM + CJS近 30 天下载 4008

A debugging library for RxJS

原始使用文档
文档目录22 节
  1. What is it?
  2. Why might you need it?
  3. Install
  4. Core concepts
  5. Module API
  6. create
  7. show
  8. log
  9. pause
  10. let
  11. debug
  12. flush
  13. plug
  14. unplug
  15. find
  16. findAll
  17. stats
  18. teardown
  19. detect
  20. Console API
  21. undo
  22. deck

rxjs-spy

GitHub License NPM version Downloads Build status dependency status devDependency Status peerDependency Status Greenkeeper badge

What is it?

rxjs-spy is a debugging library for RxJS.

Why might you need it?

The usual approach to debugging RxJS-based code involves sprinkling do operators and logging throughout composed observables. That's something that I find tedious, so I wrote this library and implemented an unobtrusive mechanism for identifying observables and logging and inspecting observable subscriptions.

If you, too, are looking for a less painful RxJS debugging experience, you might find this library useful. The engineers at Slack have adopted rxjs-spy and have this to say about it:

You might be like, "[...] but aren't Observables impossible to debug?" And you'd have been mostly right less than a year ago. But this is JavaScript and in JavaScript, the only const is change. rxjs-spy makes debugging (i.e. logging and visualizing) streams as simple as adding a tag. A tagged stream can be monitored, paused, and replayed, right from the console.

For more detail regarding how the library works and what it can do, you can have a look at:

Install

Install the package using NPM:

npm install rxjs-spy --save-dev

And import the functions for use with TypeScript or ES2015:

import { create } from "rxjs-spy";
const spy = create();

Or require the module for use with Node or a CommonJS bundler:

const { create } = require("rxjs-spy");
const spy = create();

Or include the UMD bundle for use as a script:

<script src="https://unpkg.com/rxjs@6/bundles/rxjs.umd.min.js"></script>
<script src="https://unpkg.com/rxjs-spy@7/bundles/rxjs-spy.min.umd.js"></script>
<script>
const { create } = rxjsSpy;
create();
</script>

Core concepts

rxjs-spy introduces a tag operator that can be used to identify observables. It attaches a string tag to an observable; it performs no additional processing and does not alter the observable's behaviour or value in any way.

The tag operator can be used with pipe:

import { tag } from "rxjs-spy/operators/tag";
const source = Observable.of("some-value").pipe(tag("some-tag"));

The API's methods are tag-based and tags can be matched using explicit literals, regular expressions or function predicates. For example, logging for the above tag could be enabled like this:

import { create } from "rxjs-spy";
const spy = create();
spy.log("some-tag");

// Or like this:
spy.log(/^some-tag$/);

// Or like this:
spy.log(tag => tag === "some-tag");

rxjs-spy exposes a module API intended to be called from code and a console API - via the spy global - intended for interactive use via the browser's console.

Module API

The methods in the module API are callable via imports, requires or the UMD rxjsSpy global. Most methods return a teardown function that will undo the API method's action when called.

create

function create(options: {
    [key: string]: any,
    audit?: number,
    defaultLogger?: PartialLogger,
    defaultPlugins?: boolean,
    warning?: boolean
} = {}): Teardown

Calling create attaches the spy to Observable.prototype.subscribe and returns the following interface:

interface Spy {
  readonly tick: number;
  debug(match: Match, ...notifications: Notification[]): Teardown;
  find<T extends Plugin>(ctor: Ctor<T>): T | undefined;
  findAll<T extends Plugin>(ctor: Ctor<T>): T[];
  findAll(): Plugin[];
  flush(): void;
  let(match: Match, select: (source: Observable<any>) => Observable<any>, options?: Options): Teardown;
  log(match: Match, partialLogger?: PartialLogger): Teardown;
  log(partialLogger?: PartialLogger): Teardown;
  pause(match: Match): Deck;
  plug(...plugins: Plugin[]): Teardown;
  show(match: Match, partialLogger?: PartialLogger): void;
  show(partialLogger?: PartialLogger): void;
  stats(partialLogger?: PartialLogger): void;
  teardown(): void;
  unplug(...plugins: Plugin[]): void;
}

By default, create will wire up the snapshotting plugin and numerous others. However, if the defaultPlugins option is specified as false, no plugins will be wired up and the caller can wire up plugins individually using the plug method. For example:

import { create } from "rxjs-spy";
import { GraphPlugin, SnapshotPlugin } from "rxjs-spy/plugin";
const spy = create({ defaultPlugins: false });
spy.plug(
  new GraphPlugin({ keptDuration: -1 }),
  new SnapshotPlugin(spy, { keptValues: 1 })
);

If the audit option is specified, the logging of notifications will be audited within the specified (milliseconds) duration. Each notification source will only be logged once in each duration and the number of ignored notifications (if any) will be included in the console output. This can be useful for logging high-frequency observables. audit defaults to zero - i.e. no auditing.

Options passed to create are forwarded to the plugins, so the following can be specified:

OptionTypeDescriptionDefault
keptDurationnumberThe number of milliseconds for which the subscription graph and snapshots should be kept after unsubscription occurs.30000
keptValuesnumberThe maximum number of values that should be kept in a snapshot.4
sourceMapsbooleanWhether or not the StackTracePlugin should use source maps.false

This method returns a teardown function.

show

interface Spy {
  show(
    match: string | RegExp | MatchPredicate | Observable<any>,
    partialLogger: PartialLogger = console
  ): void;
  show(
    partialLogger: PartialLogger = console
  ): void;
}

show will log information regarding the matching observables to the console or to the specified logger. If no match is specified, all tagged observables will be logged.

The logged information is retrieved from the most recent snapshot, so if snapshotting is not enabled, an error will be thrown.

log

interface Spy {
  log(
    match: string | RegExp | MatchPredicate | Observable<any>,
    partialLogger: PartialLogger = console
  ): Teardown;
  log(
    partialLogger: PartialLogger = console
  ): Teardown;
}

Wires up an instance of the log plugin for matching observables. If no match is specified, all tagged observables will be logged.

All subscribe, next, complete, error and unsubscribe notifications will be logged to the console or to the specified logger.

This method returns a teardown function.

pause

interface Spy {
  pause(
    match: string | RegExp | MatchPredicate | Observable<any>
  ): Deck;
}

Wires up an instance of the pause plugin for matching observables.

All subscriptions to matching observables will be placed into a paused state and notifications that would otherwise be emitted will be buffered inside the plugin.

This method returns a Deck instance that can be used to resume and pause the observables.

interface Deck {
  readonly paused: boolean;
  clear(): void;
  log(partialLogger: PartialLogger = console): void;
  pause(): void;
  resume(): void;
  skip(): void;
  step(): void;
  teardown(): void;
}

Calling step will release a single paused notification. The other methods to what their names suggest. Calling resume will play all buffered notifications before resuming.

let

interface Spy {
  let(
    match: string | RegExp | MatchPredicate | Observable<any>,
    select: (source: Observable<any>) => Observable<any>,
    options?: Options
  ): Teardown;
}

Wires up an instance of the let plugin for matching observables.

This is equivalent to the let operator. All subscriptions to matching observables will instead be made to the observable returned by the specified select function.

If complete option is false, completion notifications received from the selected observable will not be forwarded to subscribers.

This method returns a teardown function.

debug

interface Spy {
  debug(
    match: string | RegExp | MatchPredicate | Observable<any>,
    ...notifications: ("complete" | "error" | "next" | "subscribe" | "unsubscribe")[]
  ): Teardown;
}

Wires up an instance of the debug plugin for matching observables.

Whenever one of the specified notifications occurs, a debugger statement in the plugin will pause execution. If no notifications are specified in the call, execution will be paused when any of the notifications occurs.

This method returns a teardown function.

flush

interface Spy {
  flush(): void;
}

Calling flush will see flush called on each plugin.

If snapshotting is enabled, calling flush will release excess values and completed or errored obervables from within snapshots.

plug

interface Spy {
  plug(...plugins: Plugin[]): Teardown;
}

Wires up the specified plugin(s) and returns a teardown function.

unplug

interface Spy {
  unplug(...plugins: Plugin[]): void;
}

Removes the specified plugin(s).

find

interface Spy {
  find<T extends Plugin>(constructor: { new (...args: any[]): T }): T | undefined;
}

Returns the first plugin matching the specified constructor/class.

findAll

interface Spy {
  findAll<T extends Plugin>(constructor: { new (...args: any[]): T }): T[];
  findAll(): T[];
}

Returns all plugins matching the specified constructor/class. Or all plugins of no constructor is specified.

stats

interface Spy {
  stats(partialLogger: PartialLogger = console): void;
}

Writes, to the console, counts of the number of notifications, etc.

teardown

interface Spy {
  teardown(): void;
}

Tears down the spy.

detect

function detect(id: string): void;

Writes, to the console, any subscriptions and unsubscriptions that have occurred since the previous detect call with the specified id.

The detect method is implemented so that it can be imported and called regardless of whether or not the spy is configured. That is, calls can be left in production code, as they become no-ops. It should be imported like this:

import { detect } from "rxjs-spy/detect";

Console API

The methods in the console API are callable via the spy global and are intended to be used interactively in the browser's console.

They are identical to the methods in the spy instances created using the module API except for the fact that they do not return teardown functions. Instead, calls can be undone using the undo API method.

undo

function undo(...calls: number[]): void

When called without arguments, the undo method will display in the console a list of the rxjs-spy calls that can be undone.

Calls are listed against a call number and one or more of those numbers can be passed to undo to undo specific calls.

Undoing a spy call will undo all calls.

deck

function deck(call?: number): Deck | undefined

In the console, it's easy to forget to use a variable to capture the Deck returned by a call to pause. In those situations, you can call the deck method without an argument to see a list of numbered pause calls. Calling deck again, passing a call number, will return the Deck associated with the specified pause call.

版本与发布记录

@avalane/rxjs-spy 共发布 1 个版本,首次发布于 2025/08/16;过去 12 个月发布了 0 个版本。

版本发布日期距今
8.0.4latest2025/08/161.2 年前

关于 @avalane/rxjs-spy 的常见问题

@avalane/rxjs-spy 是什么?

A debugging library for RxJS

如何安装 @avalane/rxjs-spy?

在项目目录运行 npm install @avalane/rxjs-spy,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:rxjs(^7.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@avalane/rxjs-spy 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@avalane/rxjs-spy 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@avalane/rxjs-spy 可以商用吗?

@avalane/rxjs-spy 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@avalane/rxjs-spy 的下载量有多少?

根据 npm 官方下载统计,@avalane/rxjs-spy 在 2026/10/07 – 2026/11/05 这 30 天内被下载 4,008 次,日均约 134 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@avalane/rxjs-spy 还在维护吗?

最新版本 8.0.4 发布于 2025/08/16(1.2 年前);至今共发布 1 个版本,其中过去 12 个月发布了 0 个;首次发布于 2025/08/16。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。