## 1. Project Overview & Quickstart (ReactiveX/rxjs)

## File: README.md

# RxJS

[](https://github.com/ReactiveX/rxjs/actions/workflows/ci_main.yml?query=branch%3Amaster)
[](https://github.com/ReactiveX/rxjs/actions/workflows/release-readiness.yml?query=branch%3Amaster)
[](https://github.com/ReactiveX/rxjs/actions/workflows/observable-wpt.yml?query=branch%3Amaster)
[](https://www.npmjs.com/package/rxjs?activeTab=versions)
[](https://www.npmjs.com/package/rxjs?activeTab=versions)
[](https://www.npmjs.com/package/rxjs)
[](LICENSE.txt)

[](docs/rxjs-next/ARCHITECTURE.md#native-selection-and-polyfill-boundary)
[](docs/rxjs-next/ARCHITECTURE.md#symbol-extension-model)

RxJS is a library for composing asynchronous and event-based programs with
Observable values. This repository contains the platform-based next generation
of RxJS, planned for release as **RxJS 9**.

> RxJS 9 is prerelease work in development. The planned first beta is
> `9.0.0-beta.0`, but it has not been published to npm yet. The `next` tag still
> points to the earlier RxJS 8 prerelease, while RxJS 7 remains the production
> `latest` line and continues to be maintained.

## Why RxJS 9? What happened to RxJS 8?

RxJS 8 was real work, not a skipped release. Development began years ago and
was paused while the Web Platform Observable proposal was finalized. The new
implementation is a platform-based generation rather than a continuation of
that paused RxJS 8 branch, so it starts at version 9 to make the architectural
break unmistakable and avoid presenting the old RxJS 8 work as the released
product.

## What is different in RxJS 9?

- RxJS uses the native web-platform `Observable` when one exists and installs
  a conforming fallback only when needed.
- RxJS operators and factories are exact, module-owned Symbols. They do not add
  string-named RxJS methods to the platform API.
- Platform Observable behavior and producer-per-subscription behavior are
  explicit, separate contracts. Use `ColdObservable` when each direct
  subscription must create its own producer.
- Cancellation is built on `AbortSignal` and the platform Subscriber lifecycle.
- Published JavaScript is ESM-only. Current Node can bridge `require()` to the
  same ESM files; there is no duplicate CommonJS build.

## Preview the RxJS 9 API

The following example shows the planned beta API. Until `9.0.0-beta.0` is
published, do not use npm's `next` tag to install RxJS 9.

```ts
import { ColdObservable } from 'rxjs';
import { map } from 'rxjs/map';

const source = new ColdObservable<number>((subscriber) => {
  subscriber.next(1);
  subscriber.next(2);
  subscriber.complete();
});

source[map]((value) => value * 2).subscribe(console.log);
```

Import the Symbol and call it with bracket syntax. A platform method such as
`observable.map(project)` remains the platform contract;
`observable[map](project)` is the separately versioned RxJS contract.

## Packages and documentation

| Package                     | Purpose                                                  | Documentation                                                                                                                |
| --------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `rxjs`                      | Symbol extensions and intentional RxJS primitives        | [Package guide](packages/rxjs/README.md) · [API](packages/rxjs/docs/API.md) · [RxJS 7 migration](packages/rxjs/MIGRATION.md) |
| `@rxjs/observable-polyfill` | Conditional platform Observable fallback                 | [Package guide](packages/observable-polyfill/README.md)                                                                      |
| `@rxjs/test`                | Implementation-neutral virtual-time and marble testing   | [Package guide](packages/test/README.md)                                                                                     |
| `@rxjs/migrate`             | Deterministic migration engine and canonical agent Skill | [Package guide](packages/migrate/README.md)                                                                                  |

Release support, budgets, and exact environment gates are documented in the
[`rxjs` package](packages/rxjs/docs/RELEASE_GATES.md). The irreversible npm
publication process is the public [secure release runbook](docs/RELEASE_PROCESS.md).
The [RxJS 9 security-assurance document](packages/rxjs/docs/SECURITY_ASSURANCE.md)
explains the release evidence, verification commands, sole-maintainer model,
and OpenSSF Scorecard in context.
Repository-wide design records live in
[`docs/rxjs-next`](docs/rxjs-next/PROJECT_CHARTER.md).

## Supported environments

The planned beta supports Node 22.13+ and Node 24 as blocking lanes, with Node
26 in an advisory lane. Current Chrome, Firefox, desktop Safari, Mobile Safari,
Deno, Bun, and Webpack 5 are blocking. Every supported consumer receives the
same ESM implementation, so Deno and Bun support adds no runtime-specific
package or application-bundle code.

## Contributing

Requires Node 22.13+ and pnpm 10.34.5. Run commands from the repository root.

```sh
pnpm install
pnpm --filter rxjs exec vitest --run src
pnpm --filter rxjs run test:package
pnpm run release:check
```

Start with the [repository contribution guide](CONTRIBUTING.md) and the
[`rxjs` package contribution guide](packages/rxjs/CONTRIBUTING.md). The active
execution queue is [`PROJECT_PLAN.md`](docs/rxjs-next/PROJECT_PLAN.md).

The complete source-pinned RxJS 7 corpus intentionally retains reviewed
lifecycle and compatibility divergences, so it is migration evidence rather
than a blanket RxJS 9 compatibility gate. Focused source, package, runtime,
browser, performance, and WPT commands are the release gates.

## Community and governance

- [Code of Conduct](CODE_OF_CONDUCT.md)
- [Contribution guidelines](CONTRIBUTING.md)
- [Apache 2.0 License](LICENSE.txt)
- [Issues](https://github.com/ReactiveX/rxjs/issues)
- [Discussions](https://github.com/ReactiveX/rxjs/discussions)

---

## File: apps/rxjs.dev/content/deprecations/array-argument.md

# Array Arguments

To unify the API surface of `forkJoin` and `combineLatest` we deprecated some signatures.
Since that it is recommended to either pass an Object or an Array to these operators.


    
        This deprecation was introduced in RxJS 6.5.
    


## Operators affected by this Change

- [combineLatest](/api/index/function/combineLatest)
- [forkJoin](/api/index/function/forkJoin)

## How to Refactor

We deprecated the signatures, where just pass all Observables directly as parameters to these operators.

```ts
import {forkJoin, from} from 'rxjs';

const odd$ = from([1,3,5]);
const even$ = from([2,4,6]);

// deprecated
forkJoin(odd$, even$);
// suggested change
forkJoin([odd$, even$]);
// or
forkJoin({odd: odd$, even: even$})
```

---

## File: apps/rxjs.dev/content/deprecations/breaking-changes.md

# Breaking Changes in Version 7

## General

- **TS:** RxJS requires TS 4.2

- **rxjs-compat:** `rxjs-compat` is not published for v7

- **toPromise:** toPromise return type now returns `T | undefined` in TypeScript, which is correct, but may break builds.

- **Subscription:** `add` no longer returns an unnecessary Subscription reference. This was done to prevent confusion caused by a legacy behavior. You can now add and remove functions and Subscriptions as teardowns to and from a `Subscription` using `add` and `remove` directly. Before this, `remove` only accepted subscriptions.

- **Observable:** `lift` no longer exposed. It was _NEVER_ documented that end users of the library should be creating operators using `lift`. Lift has a [variety of issues](https://github.com/ReactiveX/rxjs/issues/5431) and was always an internal implementation detail of rxjs that might have been used by a few power users in the early days when it had the most value. The value of `lift`, originally, was that subclassed `Observable`s would compose through all operators that implemented lift. The reality is that feature is not widely known, used, or supported, and it was never documented as it was very experimental when it was first added. Until the end of v7, `lift` will remain on Observable. Standard JavaScript users will notice no difference. However, TypeScript users might see complaints about `lift` not being a member of observable. To workaround this issue there are two things you can do: 1. Rewrite your operators as [outlined in the documentation](https://rxjs.dev/guide/operators), such that they return `new Observable`. or 2. cast your observable as `any` and access `lift` that way. Method 1 is recommended if you do not want things to break when we move to version 8.

- **Subscriber:** `new Subscriber` no longer takes 0-3 arguments. To create a `Subscriber` with 0-3 arguments, use `Subscriber.create`. However, please note that there is little to no reason that you should be creating `Subscriber` references directly, and `Subscriber.create` and `new Subscriber` are both deprecated.

- **onUnhandledError:** Errors that occur during setup of an observable subscription after the subscription has emitted an error or completed will now throw in their own call stack. Before it would call `console.warn`. This is potentially breaking in edge cases for node applications, which may be configured to terminate for unhandled exceptions. In the unlikely event this affects you, you can configure the behavior to `console.warn` in the new configuration setting like so: `import { config } from 'rxjs'; config.onUnhandledError = (err) => console.warn(err);`

- **RxJS Error types** Tests that are written with naive expectations against errors may fail now that errors have a proper `stack` property. In some testing frameworks, a deep equality check on two error instances will check the values in `stack`, which could be different.

- `unsubscribe` no longer available via the `this` context of observer functions. To reenable, set `config.useDeprecatedNextContext = true` on the rxjs `config` found at `import { config } from 'rxjs';`. Note that enabling this will result in a performance penalty for all consumer subscriptions.

- Leaked implementation detail `_unsubscribeAndRecycle` of `Subscriber` has been removed. Just use new `Subscription` objects

- The static `sortActions` method on `VirtualTimeScheduler` is no longer publicly exposed by our TS types.

- `Notification.createNext(undefined)` will no longer return the exact same reference every time.

- Type signatures tightened up around `Notification` and `dematerialize`, may uncover issues with invalid types passed to those operators.

- Experimental support for `for await` has been removed. Use https://github.com/benlesh/rxjs-for-await instead.

- `ReplaySubject` no longer schedules emissions when a scheduler is provided. If you need that behavior,
  please compose in `observeOn` using `pipe`, for example: `new ReplaySubject(2, 3000).pipe(observeOn(asap))`

- **rxjs-compat:** `rxjs/Rx` is no longer a valid import site.

## Operators

### concat

- **concat:** Generic signature changed. Recommend not explicitly passing generics, just let inference do its job. If you must, cast with `as`.
- **of:** Generic signature changed, do not specify generics, allow them to be inferred or use `as`

### count

- **count:** No longer passes `source` observable as a third argument to the predicate. That feature was rarely used, and of limited value. The workaround is to simply close over the source inside of the function if you need to access it in there.

### defer

- `defer` no longer allows factories to return `void` or `undefined`. All factories passed to defer must return a proper `ObservableInput`, such as `Observable`, `Promise`, et al. To get the same behavior as you may have relied on previously, `return EMPTY` or `return of()` from the factory.

### map

- **map:** `thisArg` will now default to `undefined`. The previous default of `MapSubscriber` never made any sense. This will only affect code that calls map with a `function` and references `this` like so: `source.pipe(map(function () { console.log(this); }))`. There wasn't anything useful about doing this, so the breakage is expected to be very minimal. If anything we're no longer leaking an implementation detail.

### mergeScan

- **mergeScan:** `mergeScan` will no longer emit its inner state again upon completion.

### of

- **of:** Use with more than 9 arguments, where the last argument is a `SchedulerLike` may result in the wrong type which includes the `SchedulerLike`, even though the run time implementation does not support that. Developers should be using `scheduled` instead

### pairs

- **pairs:** `pairs` will no longer function in IE without a polyfill for `Object.entries`. `pairs` itself is also deprecated in favor of users just using `from(Object.entries(obj))`.

### race

- **race:** `race()` will no longer subscribe to subsequent observables if a provided source synchronously errors or completes. This means side effects that might have occurred during subscription in those rare cases will no longer occur.

### repeat

- An undocumented behavior where passing a negative count argument to `repeat` would result in an observable that repeats forever.

### retry

- Removed an undocumented behavior where passing a negative count argument to `retry` would result in an observable that repeats forever.

### single

- `single` operator will now throw for scenarios where values coming in are either not present, or do not match the provided predicate. Error types have thrown have also been updated, please check documentation for changes.

### skipLast

- **skipLast:** `skipLast` will no longer error when passed a negative number, rather it will simply return the source, as though `0` was passed.

### startWith

- **startWith:** `startWith` will return incorrect types when called with more than 7 arguments and a scheduler. Passing scheduler to startWith is deprecated

### take

- `take` and will now throw runtime error for arguments that are negative or NaN, this includes non-TS calls like `take()`.

### takeLast

- `takeLast` now has runtime assertions that throw `TypeError`s for invalid arguments. Calling takeLast without arguments or with an argument that is `NaN` will throw a `TypeError`

### throwError

- **throwError:** In an extreme corner case for usage, `throwError` is no longer able to emit a function as an error directly. If you need to push a function as an error, you will have to use the factory function to return the function like so: `throwError(() => functionToEmit)`, in other words `throwError(() => () => console.log('called later'))`.

### timestamp

- `timestamp` operator accepts a `TimestampProvider`, which is any object with a `now` method
  that returns a number. This means pulling in less code for the use of the `timestamp` operator. This may cause
  issues with `TestScheduler` run mode. (see [Issue here](https://github.com/ReactiveX/rxjs/issues/5553))

### zip

- **zip:** Zipping a single array will now have a different result. This is an extreme corner-case, because it is very unlikely that anyone would want to zip an array with nothing at all. The workaround would be to wrap the array in another array `zip([[1,2,3]])`. But again, that's pretty weird.

- **zip:** `zip` operators will no longer iterate provided iterables "as needed", instead the iterables will be treated as push-streams just like they would be everywhere else in RxJS. This means that passing an endless iterable will result in the thread locking up, as it will endlessly try to read from that iterable. This puts us in-line with all other Rx implementations. To work around this, it is probably best to use `map` or some combination of `map` and `zip`. For example, `zip(source$, iterator)` could be `source$.pipe(map(value => [value, iterator.next().value]))`.

## ajax

- `ajax` body serialization will now use default XHR behavior in all cases. If the body is a `Blob`, `ArrayBuffer`, any array buffer view (like a byte sequence, e.g. `Uint8Array`, etc), `FormData`, `URLSearchParams`, `string`, or `ReadableStream`, default handling is use. If the `body` is otherwise `typeof` `"object"`, then it will be converted to JSON via `JSON.stringify`, and the `Content-Type` header will be set to `application/json;charset=utf-8`. All other types will emit an error.

- The `Content-Type` header passed to `ajax` configuration no longer has any effect on the serialization behavior of the AJAX request.
- For TypeScript users, `AjaxRequest` is no longer the type that should be explicitly used to create an `ajax`. It is now `AjaxConfig`, although the two types are compatible, only `AjaxConfig` has `progressSubscriber` and `createXHR`.

- **ajax:** In an extreme corner-case... If an error occurs, the responseType is `"json"`, we're in IE, and the `responseType` is not valid JSON, the `ajax` observable will no longer emit a syntax error, rather it will emit a full `AjaxError` with more details.

- **ajax:** Ajax implementation drops support for IE10 and lower. This puts us in-line with other implementations and helps clean up code in this area

---

## File: apps/rxjs.dev/content/deprecations/index.md

# Deprecations and Breaking Changes

While the core team always tries to limit changes, sometimes we have to deprecate APIs or do breaking changes for various reasons. 
This section aims to describe some of the deprecations and breaking changes we did more in detail. Some of the changes are to extensive to describe
them appropriately in a changelog. Additionally, we can provide code examples in the documentation, to make required changes more comprehensible and therefore
lower migration efforts.

Do notice that this is not a complete list, please see the [changelog](https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md) for the complete list.

---

## File: apps/rxjs.dev/content/deprecations/multicasting.md

# Multicasting

In version 7, the multicasting APIs were simplified to just a few functions:

- [connectable](/api/index/function/connectable)
- [connect](/api/operators/connect)
- [share](/api/operators/share)

And [shareReplay](/api/operators/shareReplay) - which is a thin wrapper around the now highly-configurable [share](/api/operators/share) operator.

Other APIs that relate to multicasting are now deprecated.


    
        These deprecations were introduced in RxJS 7.0 and will become breaking in RxJS 8.
    


## APIs affected by this Change

- [ConnectableObservable](/api/index/class/ConnectableObservable)
- [multicast](/api/operators/multicast)
- [publish](/api/operators/publish)
- [publishBehavior](/api/operators/publishBehavior)
- [publishLast](/api/operators/publishLast)
- [publishReplay](/api/operators/publishReplay)
- [refCount](/api/operators/refCount)

## How to refactor

### ConnectableObservable

Instead of creating a [ConnectableObservable](/api/index/class/ConnectableObservable) instance, call the [connectable](/api/index/function/connectable) function to obtain a connectable observable.


```ts
import { ConnectableObservable, timer, Subject } from 'rxjs';

// deprecated
const tick$ = new ConnectableObservable(
  timer(1_000),
  () => new Subject());
tick$.connect();
```


```ts
import { connectable, timer, Subject } from 'rxjs';

// suggested refactor
const tick$ = connectable(timer(1_000), {
  connector: () => new Subject()
});
tick$.connect();
```

In situations in which the `refCount` method is used, the [share](/api/operators/share) operator can be used instead.


```ts
import { ConnectableObservable, timer, Subject } from 'rxjs';

// deprecated
const tick$ = new ConnectableObservable(
  timer(1_000),
  () => new Subject()
).refCount();
```


```ts
import { timer, share, Subject } from 'rxjs';

// suggested refactor
const tick$ = timer(1_000).pipe(
  share({ connector: () => new Subject() })
);
```

### multicast

Where [multicast](/api/operators/multicast) is called with a subject factory, can be replaced with [connectable](/api/index/function/connectable).


```ts
import { timer, multicast, Subject, ConnectableObservable } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  multicast(() => new Subject())
) as ConnectableObservable<number>;
```


```ts
import { connectable, timer, Subject } from 'rxjs';

// suggested refactor
const tick$ = connectable(timer(1_000), {
  connector: () => new Subject()
});
```

Where [multicast](/api/operators/multicast) is called with a subject instance, it can be replaced with [connectable](/api/index/function/connectable) and a local subject instance.


```ts
import { timer, multicast, Subject, ConnectableObservable } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  multicast(new Subject())
) as ConnectableObservable<number>;
```


```ts
import { connectable, timer, Subject } from 'rxjs';

// suggested refactor
const tick$ = connectable(timer(1_000), {
  connector: () => new Subject(),
  resetOnDisconnect: false
});
```

Where [multicast](/api/operators/multicast) is used in conjunction with [refCount](/api/operators/refCount), it can be replaced with [share](/api/index/function/connectable).


```ts
import { timer, multicast, Subject, refCount } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  multicast(() => new Subject()),
  refCount()
);
```


```ts
import { timer, share, Subject } from 'rxjs';

// suggested refactor
const tick$ = timer(1_000).pipe(
  share({ connector: () => new Subject() })
);
```

Where [multicast](/api/operators/multicast) is used with a selector, it can be replaced with [connect](/api/index/function/connect).


```ts
import { timer, multicast, Subject, combineLatest } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  multicast(
    () => new Subject(),
    (source) => combineLatest([source, source])
  )
);
```


```ts
import { timer, connect, combineLatest, Subject } from 'rxjs';

// suggested refactor
const tick$ = timer(1_000).pipe(
  connect((source) => combineLatest([source, source]), {
    connector: () => new Subject()
  })
);
```

### publish

If you're using [publish](/api/operators/publish) to create a [ConnectableObservable](/api/index/class/ConnectableObservable), you can use [connectable](/api/index/function/connectable) instead.


```ts
import { timer, publish, ConnectableObservable } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  publish()
) as ConnectableObservable<number>;
```


```ts
import { connectable, timer, Subject } from 'rxjs';

// suggested refactor
const tick$ = connectable(timer(1_000), {
  connector: () => new Subject<number>(),
  resetOnDisconnect: false
});
```

And if [refCount](/api/operators/refCount) is being applied to the result of [publish](/api/operators/publish), you can use [share](/api/operators/share) to replace both.


```ts
import { timer, publish, refCount } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  publish(),
  refCount()
);
```


```ts
import { timer, share } from 'rxjs';

// suggested refactor
const tick$ = timer(1_000).pipe(
  share({
    resetOnError: false,
    resetOnComplete: false,
    resetOnRefCountZero: false
  })
);
```

If [publish](/api/operators/publish) is being called with a selector, you can use the [connect](/api/operators/connect) operator instead.


```ts
import { timer, publish, combineLatest } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  publish((source) => combineLatest([source, source]))
);
```


```ts
import { timer, connect, combineLatest } from 'rxjs';

// suggested refactor
const tick$ = timer(1_000).pipe(
  connect((source) => combineLatest([source, source]))
);
```

### publishBehavior

If you're using [publishBehavior](/api/operators/publishBehavior) to create a [ConnectableObservable](/api/index/class/ConnectableObservable), you can use [connectable](/api/index/function/connectable) and a [BehaviorSubject](api/index/class/BehaviorSubject) instead.


```ts
import { timer, publishBehavior, ConnectableObservable } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  publishBehavior(0)
) as ConnectableObservable<number>;
```


```ts
import { connectable, timer, BehaviorSubject } from 'rxjs';

// suggested refactor
const tick$ = connectable(timer(1_000), {
  connector: () => new BehaviorSubject(0),
  resetOnDisconnect: false
});
```

And if [refCount](/api/operators/refCount) is being applied to the result of [publishBehavior](/api/operators/publishBehavior), you can use the [share](/api/operators/share) operator - with a [BehaviorSubject](api/index/class/BehaviorSubject) connector - to replace both.


```ts
import { timer, publishBehavior, refCount } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  publishBehavior(0),
  refCount()
);
```


```ts
import { timer, share, BehaviorSubject } from 'rxjs';

// suggested refactor
const tick$ = timer(1_000).pipe(
  share({
    connector: () => new BehaviorSubject(0),
    resetOnError: false,
    resetOnComplete: false,
    resetOnRefCountZero: false
  })
);
```

### publishLast

If you're using [publishLast](/api/operators/publishLast) to create a [ConnectableObservable](/api/index/class/ConnectableObservable), you can use [connectable](/api/index/function/connectable) and an [AsyncSubject](api/index/class/AsyncSubject) instead.


```ts
import { timer, publishLast, ConnectableObservable } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  publishLast()
) as ConnectableObservable<number>;
```


```ts
import { connectable, timer, AsyncSubject } from 'rxjs';

// suggested refactor
const tick$ = connectable(timer(1_000), {
  connector: () => new AsyncSubject<number>(),
  resetOnDisconnect: false
});
```

And if [refCount](/api/operators/refCount) is being applied to the result of [publishLast](/api/operators/publishLast), you can use the [share](/api/operators/share) operator - with an [AsyncSubject](api/index/class/AsyncSubject) connector - to replace both.


```ts
import { timer, publishLast, refCount } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  publishLast(),
  refCount()
);
```


```ts
import { timer, share, AsyncSubject } from 'rxjs';

// suggested refactor
const tick$ = timer(1_000).pipe(
  share({
    connector: () => new AsyncSubject(),
    resetOnError: false,
    resetOnComplete: false,
    resetOnRefCountZero: false
  })
);
```

### publishReplay

If you're using [publishReplay](/api/operators/publishReplay) to create a [ConnectableObservable](/api/index/class/ConnectableObservable), you can use [connectable](/api/index/function/connectable) and a [ReplaySubject](api/index/class/ReplaySubject) instead.


```ts
import { timer, publishReplay, ConnectableObservable } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  publishReplay(1)
) as ConnectableObservable<number>;
```


```ts
import { connectable, timer, ReplaySubject } from 'rxjs';

// suggested refactor
const tick$ = connectable(timer(1_000), {
  connector: () => new ReplaySubject<number>(1),
  resetOnDisconnect: false
});
```

And if [refCount](/api/operators/refCount) is being applied to the result of [publishReplay](/api/operators/publishReplay), you can use the [share](/api/operators/share) operator - with a [ReplaySubject](api/index/class/ReplaySubject) connector - to replace both.


```ts
import { timer, publishReplay, refCount } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  publishReplay(1),
  refCount()
);
```


```ts
import { timer, share, ReplaySubject } from 'rxjs';

// suggested refactor
const tick$ = timer(1_000).pipe(
  share({
    connector: () => new ReplaySubject(1),
    resetOnError: false,
    resetOnComplete: false,
    resetOnRefCountZero: false
  })
);
```

If [publishReplay](/api/operators/publishReplay) is being called with a selector, you can use the [connect](/api/operators/connect) operator - with a [ReplaySubject](api/index/class/ReplaySubject) connector - instead.


```ts
import { timer, publishReplay, combineLatest } from 'rxjs';

// deprecated
const tick$ = timer(1_000).pipe(
  publishReplay(1, undefined, (source) => combineLatest([source, source]))
);
```


```ts
import { timer, connect, combineLatest, ReplaySubject } from 'rxjs';

// suggested refactor
const tick$ = timer(1_000).pipe(
  connect((source) => combineLatest([source, source]), {
    connector: () => new ReplaySubject(1)
  })
);
```

### refCount

Instead of applying the [refCount](/api/operators/refCount) operator to the [ConnectableObservable](/api/index/class/ConnectableObservable) obtained from a [multicast](/api/operators/multicast)
or [publish](/api/operators/publish) operator, use the [share](/api/operators/share) operator to replace both.

The properties passed to [share](/api/operators/share) will depend upon the operators that are being replaced. The refactors for using [refCount](/api/operators/refCount) with [multicast](/api/operators/multicast), [publish](/api/operators/publish), [publishBehavior](/api/operators/publishBehavior), [publishLast](/api/operators/publishLast) and [publishReplay](/api/operators/publishReplay) are detailed above.

---

## File: apps/rxjs.dev/content/deprecations/resultSelector.md

# ResultSelector Parameter

Some operator supported a resultSelector argument that acted as mapping function on the result of that operator.
The same behavior can be reproduced with the `map` operator, therefore this argument became deprecated.


    
        This deprecation was introduced in RxJS 6.0 and will become breaking with RxJS 8.
    


There were two reasons for actually deprecating those parameters:

1. It increases the bundle size of every operator
2. In some scenarios values had to be retained in memory causing a general memory pressure

## Operators affected by this Change

- [concatMap](/api/operators/concatMap)
- [concatMapTo](/api/operators/concatMapTo)
- [exhaustMap](/api/operators/exhaustMap)
- [mergeMap](/api/operators/mergeMap)
- [mergeMapTo](/api/operators/mergeMapTo)
- [switchMap](/api/operators/switchMap)
- [switchMapTo](/api/operators/switchMapTo)

## How to Refactor

Instead of using the `resultSelector` Argument, you can leverage the [`map`](/api/operators/map) operator on the inner Observable:


```ts
import { fromEvent, switchMap, interval, map } from 'rxjs';

// deprecated
fromEvent(document, 'click').pipe(
  switchMap((x) => interval(1000), (_, x) => x + 1)
);
// suggested change
fromEvent(document, 'click').pipe(
  switchMap((x) => interval(1000).pipe(map((x) => x + 1)))
);
```

---

## File: apps/rxjs.dev/content/deprecations/scheduler-argument.md

# Scheduler Argument

To limit the API surface of some operators, but also prepare for a [major refactoring in V8](https://github.com/ReactiveX/rxjs/pull/4583), we
agreed on deprecating the `scheduler` argument from many operators. It solely deprecates those methods where this argument is rarely used. So `time` related
operators, like [`interval`](https://rxjs.dev/api/index/function/interval) are not affected by this deprecation.

To support this transition the [scheduled creation function](/api/index/function/scheduled) was added.


    
        This deprecation was introduced in RxJS 6.5 and will become breaking with RxJS 8.
    


## Operators affected by this Change

- [from](/api/index/function/from)
- [of](/api/index/function/of)
- [merge](/api/index/function/merge)
- [concat](/api/index/function/concat)
- [startWith](/api/operators/startWith)
- [endWith](/api/operators/endWith)
- [combineLatest](/api/index/function/combineLatest)

## How to Refactor

If you use any operator from the above list and you're passing the `scheduler` argument, you have three potential refactoring options.

### Refactoring of `of` and `from`

`scheduled` is kinda copying the behavior of `from`. Therefore if you used `from` with a `scheduler` argument, you can just replace them.

For the `of` creation function you need to replace this Observable with `scheduled` and instead of passing the `scheduler` argument to `of` pass it to `scheduled`.
Following code example demonstrate this process.

```ts
import { of, asyncScheduler, scheduled } from 'rxjs';

// Deprecated approach
of(1, 2, 3, asyncScheduler).subscribe((x) => console.log(x));
// suggested approach
scheduled([1, 2, 3], asyncScheduler).subscribe((x) => console.log(x));
```

### Refactoring of `merge`, `concat`, `combineLatest`, `startWith` and `endWith`

In case you used to pass a scheduler argument to one of these operators you probably had code like this:

```ts
import { concat, of, asyncScheduler } from 'rxjs';

concat(of('hello '), of('World'), asyncScheduler).subscribe((x) => console.log(x));
```

To work around this deprecation you can leverage the [`scheduled`](/api/index/function/scheduled) function.

```ts
import { scheduled, of, asyncScheduler, concatAll } from 'rxjs';

scheduled([of('hello '), of('World')], asyncScheduler)
  .pipe(concatAll())
  .subscribe((x) => console.log(x));
```

You can apply this pattern to refactor deprecated usage of `concat`, `startWith` and `endWith` but do notice that you will want to use [mergeAll](/api/operators/mergeAll) to refactor the deprecated usage of `merge`.

With `combineLatest`, you will want to use [combineLatestAll](/api/operators/combineLatestAll)

E.g. code that used to look like this:

```ts
import { combineLatest, of, asyncScheduler } from 'rxjs';

combineLatest(of('hello '), of('World'), asyncScheduler).subscribe(console.log);
```

would become:

```ts
import { scheduled, of, asyncScheduler, combineLatestAll } from 'rxjs';

scheduled([of('hello '), of('World')], asyncScheduler)
  .pipe(combineLatestAll())
  .subscribe((x) => console.log(x));
```

---

## File: apps/rxjs.dev/content/deprecations/subscribe-arguments.md

# Subscribe Arguments

You might have seen that we deprecated some signatures of the `subscribe` method, which might have caused some confusion.
The `subscribe` method itself is not deprecated. This deprecation also affects the [`tap` operator](../../api/operators/tap), as tap supports the same signature as the `subscribe` method.

This is to get ready for a future where we may allow configuration of `subscribe` via the second argument, for things like `AbortSignal` or the like (imagine `source$.subscribe(fn, { signal })`, etc). This deprecation is also because 2-3 function arguments can contribute to harder-to-read code. For example someone could name functions poorly and confuse the next reader: `source$.subscribe(doSomething, doSomethingElse, lol)` With that signature, you have to know unapparent details about `subscribe`, where using a partial observer solves that neatly: `source$.subscribe({ next: doSomething, error: doSomethingElse, complete: lol })`.


    
        This deprecation was introduced in RxJS 6.4.
    


In short we deprecated all signatures where you specified an anonymous `error` or `complete` callback and passed an empty function to one of the callbacks before. 

## What Signature is affected

**We have deprecated all signatures of `subscribe` that take more than 1 argument.** 

We deprecated signatures for just passing the `complete` callback.

```ts
import { of } from 'rxjs';

// deprecated
of([1,2,3]).subscribe(null, null, console.info); // difficult to read
// suggested change
of([1,2,3]).subscribe({complete: console.info});
```

Similarly, we also deprecated signatures for solely passing the `error` callback.

```ts
import { throwError } from 'rxjs';

// deprecated 
throwError('I am an error').subscribe(null, console.error);
// suggested change
throwError('I am an error').subscribe({error: console.error});
```

Do notice, in general it is recommended only to use the anonymous function if you only specify the `next` callback otherwise
we recommend to pass an `Observer`

```ts
import { of } from 'rxjs';

// recommended 
of([1,2,3]).subscribe((v) => console.info(v));
// also recommended
of([1,2,3]).subscribe({
    next: (v) => console.log(v),
    error: (e) => console.error(e),
    complete: () => console.info('complete') 
})
```

---

## File: apps/rxjs.dev/content/deprecations/to-promise.md

# Conversion to Promises

The similarity between Observables and Promises is that both [collections](/guide/observable) may produce values over
time, but the difference is that Observables may produce none or more than one value, while Promises produce only one
value when resolved successfully.

## Issues

For this reason, in RxJS 7, the return type of the Observable's [`toPromise()`](/api/index/class/Observable#toPromise)
method has been fixed to better reflect the fact that Observables can yield zero values. This may be a **breaking
change** to some projects as the return type was changed from `Promise<T>` to `Promise<T | undefined>`.

Also, `toPromise()` method name was never indicating what emitted value a Promise will resolve with because Observables
can produce multiple values over time. When converting to a Promise, you might want to choose which value to pick -
either the first value that has arrived or the last one. To fix all these issues, we decided to deprecate `toPromise()`,
and to introduce the two new helper functions for conversion to Promises.

## Use one of the two new functions

As a replacement to the deprecated `toPromise()` method, you should use one of the two built in static conversion
functions {@link firstValueFrom} or {@link lastValueFrom}.

### `lastValueFrom`

The `lastValueFrom` is almost exactly the same as `toPromise()` meaning that it will resolve with the last value that has
arrived when the Observable completes, but with the difference in behavior when Observable completes without emitting a
single value. When Observable completes without emitting, `toPromise()` will successfully resolve with `undefined` (thus
the return type change), while the `lastValueFrom` will reject with the {@link EmptyError}. Thus, the return type of the
`lastValueFrom` is `Promise<T>`, just like `toPromise()` had in RxJS 6.

#### Example

```ts
import { interval, take, lastValueFrom } from 'rxjs';

async function execute() {
  const source$ = interval(2000).pipe(take(10));
  const finalNumber = await lastValueFrom(source$);
  console.log(`The final number is ${finalNumber}`);
}

execute();

// Expected output:
// "The final number is 9"
```

### `firstValueFrom`

However, you might want to take the first value as it arrives without waiting an Observable to complete, thus you can
use `firstValueFrom`. The `firstValueFrom` will resolve a Promise with the first value that was emitted from the
Observable and will immediately unsubscribe to retain resources. The `firstValueFrom` will also reject with an
{@link EmptyError} if the Observable completes with no values emitted.

#### Example

```ts
import { interval, firstValueFrom } from 'rxjs';

async function execute() {
  const source$ = interval(2000);
  const firstNumber = await firstValueFrom(source$);
  console.log(`The first number is ${firstNumber}`);
}

execute();

// Expected output:
// "The first number is 0"
```

Both functions will return a Promise that rejects if the source Observable errors. The Promise
will reject with the same error that the Observable has errored with.

## Use default value

If you don't want Promises created by `lastValueFrom` or `firstValueFrom` to reject with {@link EmptyError} if there
were no emissions before completion, you can use the second parameter. The second parameter is expected to be an object
with `defaultValue` parameter. The value in the `defaultValue` will be used to resolve a Promise when source Observable
completes without emitted values.

```ts
import { firstValueFrom, EMPTY } from 'rxjs';

const result = await firstValueFrom(EMPTY, { defaultValue: 0 });
console.log(result);

// Expected output:
// 0
```

## Warning

Only use `lastValueFrom` function if you _know_ an Observable will eventually complete. The `firstValueFrom` function should
be used if you _know_ an Observable will emit at least one value _or_ will eventually complete. If the source Observable
does not complete or emit, you will end up with a Promise that is hung up, and potentially all of the state of an async
function hanging out in memory. To avoid this situation, look into adding something like {@link timeout}, {@link take},
{@link takeWhile}, or {@link takeUntil} amongst others.

---

## File: apps/rxjs.dev/content/guide/testing/marble-testing.md

# Testing RxJS Code with Marble Diagrams


  This guide refers to usage of marble diagrams when using the new `testScheduler.run(callback)`. Some details here do not apply to using the TestScheduler manually, without using the `run()` helper.


We can test our _asynchronous_ RxJS code _synchronously_ and deterministically by virtualizing time using the TestScheduler. **Marble diagrams** provide a visual way for us to represent the behavior of an Observable. We can use them to assert that a particular Observable behaves as expected, as well as to create [hot and cold Observables](https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339) we can use as mocks.

> At this time, the TestScheduler can only be used to test code that uses RxJS schedulers - `AsyncScheduler`, etc. If the code consumes a Promise, for example, it cannot be reliably tested with `TestScheduler`, but instead should be tested more traditionally. See the [Known Issues](#known-issues) section for more details.

```ts
import { TestScheduler } from 'rxjs/testing';
import { throttleTime } from 'rxjs';

const testScheduler = new TestScheduler((actual, expected) => {
  // asserting the two objects are equal - required
  // for TestScheduler assertions to work via your test framework
  // e.g. using chai.
  expect(actual).deep.equal(expected);
});

// This test runs synchronously.
it('generates the stream correctly', () => {
  testScheduler.run((helpers) => {
    const { cold, time, expectObservable, expectSubscriptions } = helpers;
    const e1 = cold(' -a--b--c---|');
    const e1subs = '  ^----------!';
    const t = time('   ---|       '); // t = 3
    const expected = '-a-----c---|';

    expectObservable(e1.pipe(throttleTime(t))).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });
});
```

## API

The callback function you provide to `testScheduler.run(callback)` is called with `helpers` object that contains functions you'll use to write your tests.


  
    When the code inside this callback is being executed, any operator that uses timers/AsyncScheduler (like delay, debounceTime, etc.,) will automatically use the TestScheduler instead, so that we have "virtual time". You do not need to pass the TestScheduler to them, like in the past.
  


```ts
testScheduler.run((helpers) => {
  const { cold, hot, expectObservable, expectSubscriptions, flush, time, animate } = helpers;
  // use them
});
```

Although `run()` executes entirely synchronously, the helper functions inside your callback function do not! These functions **schedule assertions** that will execute either when your callback completes or when you explicitly call `flush()`. Be wary of calling synchronous assertions, for example `expect`, from your testing library of choice, from within the callback. See [Synchronous Assertion](#synchronous-assertion) for more information on how to do this.

- `cold(marbleDiagram: string, values?: object, error?: any)` - creates a "cold" observable whose subscription starts when the test begins.
- `hot(marbleDiagram: string, values?: object, error?: any)` - creates a "hot" observable (like a subject) that will behave as though it's already "running" when the test begins. An interesting difference is that `hot` marbles allow a `^` character to signal where the "zero frame" is. That is the point at which the subscription to observables being tested begins.
- `expectObservable(actual: Observable<T>, subscriptionMarbles?: string).toBe(marbleDiagram: string, values?: object, error?: any)` - schedules an assertion for when the TestScheduler flushes. Give `subscriptionMarbles` as parameter to change the schedule of subscription and unsubscription. If you don't provide the `subscriptionMarbles` parameter it will subscribe at the beginning and never unsubscribe. Read below about subscription marble diagram.
- `expectSubscriptions(actualSubscriptionLogs: SubscriptionLog[]).toBe(subscriptionMarbles: string)` - like `expectObservable` schedules an assertion for when the testScheduler flushes. Both `cold()` and `hot()` return an observable with a property `subscriptions` of type `SubscriptionLog[]`. Give `subscriptions` as parameter to `expectSubscriptions` to assert whether it matches the `subscriptionsMarbles` marble diagram given in `toBe()`. Subscription marble diagrams are slightly different than Observable marble diagrams. Read more below.
- `flush()` - immediately starts virtual time. Not often used since `run()` will automatically flush for you when your callback returns, but in some cases you may wish to flush more than once or otherwise have more control.
- `time()` - converts marbles into a number indicating number of frames. It can be used by operators expecting a specific timeout. It measures time based on the position of the complete (`|`) signal:

  ```ts
  testScheduler.run((helpers) => {
    const { time, cold } = helpers;
    const source = cold('---a--b--|');
    const t = time('        --|    ');
    //                         --|
    const expected = '   -----a--b|';
    const result = source.pipe(delay(t));
    expectObservable(result).toBe(expected);
  });
  ```

- `animate()` - specifies when requested animation frames will be 'painted'. `animate` accepts a marble diagram and each value emission in the diagram indicates when a 'paint' occurs - at which time, any queued `requestAnimationFrame` callbacks will be executed. Call `animate` at the beginning of your test and align the marble diagrams so that it's clear when the callbacks will be executed:

  ```ts
  testScheduler.run((helpers) => {
    const { animate, cold } = helpers;
    animate('              ---x---x---x---x');
    const requests = cold('-r-------r------');
    /* ... */
    const expected = '     ---a-------b----';
  });
  ```

## Marble syntax

In the context of TestScheduler, a marble diagram is a string containing special syntax representing events happening over virtual time. Time progresses by _frames_. The first character of any marble string always represents the _zero frame_, or the start of time. Inside of `testScheduler.run(callback)` the frameTimeFactor is set to 1, which means one frame is equal to one virtual millisecond.

How many virtual milliseconds one frame represents depends on the value of `TestScheduler.frameTimeFactor`. For legacy reasons the value of `frameTimeFactor` is 1 _only_ when your code inside the `testScheduler.run(callback)` callback is running. Outside of it, it's set to 10. This will likely change in a future version of RxJS so that it is always 1.

> IMPORTANT: This syntax guide refers to usage of marble diagrams when using the new `testScheduler.run(callback)`. The semantics of marble diagrams when using the TestScheduler manually are different, and some features like the new time progression syntax are not supported.

- `' '` whitespace: horizontal whitespace is ignored, and can be used to help vertically align multiple marble diagrams.
- `'-'` frame: 1 "frame" of virtual time passing (see above description of frames).
- `[0-9]+[ms|s|m]` time progression: the time progression syntax lets you progress virtual time by a specific amount. It's a number, followed by a time unit of `ms` (milliseconds), `s` (seconds), or `m` (minutes) without any space between them, e.g. `a 10ms b`. See [Time progression syntax](#time-progression-syntax) for more details.
- `'|'` complete: The successful completion of an observable. This is the observable producer signaling `complete()`.
- `'#'` error: An error terminating the observable. This is the observable producer signaling `error()`.
- `[a-z0-9]` e.g. `'a'` any alphanumeric character: Represents a value being emitted by the producer signaling `next()`. Also consider that you could map this into an object or an array like this:


  ```ts
  const expected = '400ms (a-b|)';
  const values = {
    a: 'value emitted',
    b: 'another value emitted',
  };

  expectObservable(someStreamForTesting).toBe(expected, values);

  // This would work also
  const expected = '400ms (0-1|)';
  const values = [
    'value emitted',
    'another value emitted'
  ];

  expectObservable(someStreamForTesting).toBe(expected, values);
  ```

- `'()'` sync groupings: When multiple events need to be in the same frame synchronously, parentheses are used to group those events. You can group next'd values, a completion, or an error in this manner. The position of the initial `(` determines the time at which its values are emitted. While it can be counter-intuitive at first, after all the values have synchronously emitted time will progress a number of frames equal to the number of ASCII characters in the group, including the parentheses. e.g. `'(abc)'` will emit the values of a, b, and c synchronously in the same frame and then advance virtual time by 5 frames, `'(abc)'.length === 5`. This is done because it often helps you vertically align your marble diagrams, but it's a known pain point in real-world testing. [Learn more about known issues](#known-issues).
- `'^'` subscription point: (hot observables only) shows the point at which the tested observables will be subscribed to the hot observable. This is the "zero frame" for that observable, every frame before the `^` will be negative. Negative time might seem pointless, but there are in fact advanced cases where this is necessary, usually involving ReplaySubjects.

### Time progression syntax

The new time progression syntax takes inspiration from the CSS duration syntax. It's a number (integer or floating point) immediately followed by a unit; ms (milliseconds), s (seconds), m (minutes). e.g. `100ms`, `1.4s`, `5.25m`.

When it's not the first character of the diagram it must be padded a space before/after to disambiguate it from a series of marbles. e.g. `a 1ms b` needs the spaces because `a1msb` will be interpreted as `['a', '1', 'm', 's', 'b']` where each of these characters is a value that will be next()'d as-is.

**NOTE**: You may have to subtract 1 millisecond from the time you want to progress because the alphanumeric marbles (representing an actual emitted value) _advance time 1 virtual frame_ themselves already, after they emit. This can be counter-intuitive and frustrating, but for now it is indeed correct.


```ts
const input = ' -a-b-c|';
const expected = '-- 9ms a 9ms b 9ms (c|)';

// Depending on your personal preferences you could also
// use frame dashes to keep vertical alignment with the input.
// const input = ' -a-b-c|';
// const expected = '------- 4ms a 9ms b 9ms (c|)';
// or
// const expected = '-----------a 9ms b 9ms (c|)';

const result = cold(input).pipe(
  concatMap((d) => of(d).pipe(
    delay(10)
  ))
);

expectObservable(result).toBe(expected);
```

### Examples

`'-'` or `'------'`: Equivalent to {@link NEVER}, or an observable that never emits or errors or completes.

`|`: Equivalent to {@link EMPTY}, or an observable that never emits and completes immediately.

`#`: Equivalent to {@link throwError}, or an observable that never emits and errors immediately.

`'--a--'`: An observable that waits 2 "frames", emits value `a` on frame 2 and then never completes.

`'--a--b--|'`: On frame 2 emit `a`, on frame 5 emit `b`, and on frame 8, `complete`.

`'--a--b--#'`: On frame 2 emit `a`, on frame 5 emit `b`, and on frame 8, `error`.

`'-a-^-b--|'`: In a hot observable, on frame -2 emit `a`, then on frame 2 emit `b`, and on frame 5, `complete`.

`'--(abc)-|'`: on frame 2 emit `a`, `b`, and `c`, then on frame 8, `complete`.

`'-----(a|)'`: on frame 5 emit `a` and `complete`.

`'a 9ms b 9s c|'`: on frame 0 emit `a`, on frame 10 emit `b`, on frame 9,011 emit `c`, then on frame 9,012 `complete`.

`'--a 2.5m b'`: on frame 2 emit `a`, on frame 150,003 emit `b` and never complete.

## Subscription marbles

The `expectSubscriptions` helper allows you to assert that a `cold()` or `hot()` Observable you created was subscribed/unsubscribed to at the correct point in time. The `subscriptionMarbles` parameter to `expectObservable` allows your test to defer subscription to a later virtual time, and/or unsubscribe even if the observable being tested has not yet completed.

The subscription marble syntax is slightly different to conventional marble syntax.

- `'-'` time: 1 frame time passing.
- `[0-9]+[ms|s|m]` time progression: the time progression syntax lets you progress virtual time by a specific amount. It's a number, followed by a time unit of `ms` (milliseconds), `s` (seconds), or `m` (minutes) without any space between them, e.g. `a 10ms b`. See [Time progression syntax](#time-progression-syntax) for more details.
- `'^'` subscription point: shows the point in time at which a subscription happens.
- `'!'` unsubscription point: shows the point in time at which a subscription is unsubscribed.

There should be **at most one** `^` point in a subscription marble diagram, and **at most one** `!` point. Other than that, the `-` character is the only one allowed in a subscription marble diagram.

### Examples

`'-'` or `'------'`: no subscription ever happened.

`'--^--'`: a subscription happened after 2 "frames" of time passed, and the subscription was not unsubscribed.

`'--^--!-'`: on frame 2 a subscription happened, and on frame 5 was unsubscribed.

`'500ms ^ 1s !'`: on frame 500 a subscription happened, and on frame 1,501 was unsubscribed.

Given a hot source, test multiple subscribers that subscribe at different times:

```ts
testScheduler.run(({ hot, expectObservable }) => {
  const source = hot('--a--a--a--a--a--a--a--');
  const sub1 = '      --^-----------!';
  const sub2 = '      ---------^--------!';
  const expect1 = '   --a--a--a--a--';
  const expect2 = '   -----------a--a--a-';

  expectObservable(source, sub1).toBe(expect1);
  expectObservable(source, sub2).toBe(expect2);
});
```

Manually unsubscribe from a source that will never complete:

```ts
it('should repeat forever', () => {
  const testScheduler = createScheduler();

  testScheduler.run(({ expectObservable }) => {
    const foreverStream$ = interval(1).pipe(mapTo('a'));

    // Omitting this arg may crash the test suite.
    const unsub = '------!';

    expectObservable(foreverStream$, unsub).toBe('-aaaaa');
  });
});
```

## Synchronous Assertion

Sometimes, we need to assert changes in state _after_ an observable stream has completed - such as when a side effect like `tap` updates a variable. Outside of Marbles testing with TestScheduler, we might think of this as creating a delay or waiting before making our assertion.

For example:

```ts
let eventCount = 0;

const s1 = cold('--a--b|', { a: 'x', b: 'y' });

// side effect using 'tap' updates a variable
const result = s1.pipe(tap(() => eventCount++));

expectObservable(result).toBe('--a--b|', { a: 'x', b: 'y' });

// flush - run 'virtual time' to complete all outstanding hot or cold observables
flush();

expect(eventCount).toBe(2);
```

In the above situation we need the observable stream to complete so that we can test the variable was set to the correct value. The TestScheduler runs in 'virtual time' (synchronously), but doesn't normally run (and complete) until the testScheduler callback returns. The flush() method manually triggers the virtual time so that we can test the local variable after the observable completes.

---

## Known issues

### RxJS code that consumes Promises cannot be directly tested

If you have RxJS code that uses asynchronous scheduling - e.g. Promises, etc. - you can't reliably use marble diagrams _for that particular code_. This is because those other scheduling methods won't be virtualized or known to TestScheduler.

The solution is to test that code in isolation, with the traditional asynchronous testing methods of your testing framework. The specifics depend on your testing framework of choice, but here's a pseudo-code example:

```ts
// Some RxJS code that also consumes a Promise, so TestScheduler won't be able
// to correctly virtualize and the test will always be really asynchronous.
const myAsyncCode = () => from(Promise.resolve('something'));

it('has async code', (done) => {
  myAsyncCode().subscribe((d) => {
    assertEqual(d, 'something');
    done();
  });
});
```

On a related note, you also can't currently assert delays of zero, even with `AsyncScheduler`, e.g. `delay(0)` is like saying `setTimeout(work, 0)`. This schedules a new ["task" aka "macrotask"](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/), so it's asynchronous, but without an explicit passage of time.

### Behavior is different outside of `testScheduler.run(callback)`

The `TestScheduler` has been around since v5, but was actually intended for testing RxJS itself by the maintainers, rather than for use in regular user apps. Because of this, some of the default behaviors and features of the TestScheduler did not work well (or at all) for users. In v6 we introduced the `testScheduler.run(callback)` method which allowed us to provide new defaults and features in a non-breaking way, but it's still possible to [use the TestScheduler outside](https://github.com/ReactiveX/rxjs/blob/7113ae4b451dd8463fae71b68edab96079d089df/docs_app/content/guide/testing/internal-marble-tests.md) of `testScheduler.run(callback)`. It's important to note that if you do so, there are some major differences in how it will behave.

- `TestScheduler` helper methods have more verbose names, like `testScheduler.createColdObservable()` instead of `cold()`.
- The testScheduler instance is _not_ automatically used by operators that use `AsyncScheduler`, e.g. `delay`, `debounceTime`, etc., so you have to explicitly pass it to them.
- There is NO support for time progression syntax e.g. `-a 100ms b-|`.
- 1 frame is 10 virtual milliseconds by default. i.e. `TestScheduler.frameTimeFactor = 10`.
- Each whitespace `' '` equals 1 frame, same as a hyphen `'-'`.
- There is a hard maximum number of frames set at 750 i.e. `maxFrames = 750`. After 750 they are silently ignored.
- You must explicitly flush the scheduler.

While at this time usage of the TestScheduler outside of `testScheduler.run(callback)` has not been officially deprecated, it is discouraged because it is likely to cause confusion.

## 2. Official Technical Reference & Guides (ReactiveX/rxjs-docs)

[](https://travis-ci.org/ReactiveX/rxjs-docs)

# THIS REPOSITORY IS DEPRECATED. THE RXJS DOCS ARE DEVELOPED AT THE [RXJS REPO](https://github.com/ReactiveX/rxjs) 

# [rxjs-docs](http://rxjsdocs.com/)
The home for new work on the new RxJS docs (RxJS v5 and up).
Website (currently beta) can be found [here](http://rxjsdocs.com/). 
We highly welcome any kind of feedback or contribution.

License is the same as the RxJS project: https://github.com/reactivex/rxjs

[Apache 2.0 License](LICENSE.txt)
- [Code of Conduct](CODE_OF_CONDUCT.md)
- [Contribution Guidelines](CONTRIBUTING.md)

## Important

By contributing or commenting on issues in this repository, whether you've read them or not, you're agreeing to the [Contributor Code of Conduct](CODE_OF_CONDUCT.md). Much like traffic laws, ignorance doesn't grant you immunity.

## Goals

- Serve updated docs for RxJs
- Serve multiple translations for the docs
- Provide working examples

## Contributing

More detailed information can be found in the [Contribution Guidelines](CONTRIBUTING.md)

## Building/Testing

The build and test structure is fairly primitive at the moment. There are various npm scripts that can be run:

- start: runs the dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
- test: runs tests with `jasmine`, must have built prior to running.
- build: build artifacts will be stored in the `dist/` directory
- build-prod: builds for production using the `--prod` flag
- commit: runs git commit wizard for passing rxjs-github-bot message validator

## Committing
It is strongly recommended that when creating a commit, you follow this procedure to start the commit wizard. It will aid you on creating valid commit messages.

```shell
git add .
npm run commit
```