Skip to content

Commit 45f909e

Browse files
alxhubatscott
authored andcommitted
Revert "refactor(core): support an opt-in sync version of toObservable (angular#60640)" (angular#60449)
This reverts commit 57a240b. We're no longer attempting to convert `toObservable` to a synchronous API. PR Close angular#60449
1 parent 1c1ad12 commit 45f909e

File tree

3 files changed

+0
-154
lines changed

3 files changed

+0
-154
lines changed

goldens/public-api/core/rxjs-interop/index.api.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ export function toObservable<T>(source: Signal<T>, options?: ToObservableOptions
3939

4040
// @public
4141
export interface ToObservableOptions {
42-
// @deprecated
43-
forceSyncFirstEmit?: true;
4442
injector?: Injector;
4543
}
4644

packages/core/rxjs-interop/src/to_observable.ts

Lines changed: 0 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
Signal,
1616
untracked,
1717
} from '../../src/core';
18-
import {SIGNAL, ReactiveNode} from '../../primitives/signals';
1918
import {Observable, ReplaySubject} from 'rxjs';
2019

2120
/**
@@ -31,16 +30,6 @@ export interface ToObservableOptions {
3130
* will be used.
3231
*/
3332
injector?: Injector;
34-
35-
/**
36-
* Temporary option for forcing a synchronous emit of the signal's initial value.
37-
*
38-
* This will eventually become the default behavior, but is opt-in to allow a short migration
39-
* period.
40-
*
41-
* @deprecated will become default behavior
42-
*/
43-
forceSyncFirstEmit?: true;
4433
}
4534

4635
/**
@@ -53,10 +42,6 @@ export interface ToObservableOptions {
5342
* @developerPreview
5443
*/
5544
export function toObservable<T>(source: Signal<T>, options?: ToObservableOptions): Observable<T> {
56-
if (options?.forceSyncFirstEmit === true) {
57-
return toObservableNext(source, options);
58-
}
59-
6045
!options?.injector && assertInInjectionContext(toObservable);
6146
const injector = options?.injector ?? inject(Injector);
6247
const subject = new ReplaySubject<T>(1);
@@ -82,88 +67,3 @@ export function toObservable<T>(source: Signal<T>, options?: ToObservableOptions
8267

8368
return subject.asObservable();
8469
}
85-
86-
/**
87-
* New version of `toObservable` with always-synchronous first emit.
88-
*
89-
* This will eventually replace the other implementation.
90-
*/
91-
function toObservableNext<T>(source: Signal<T>, options?: ToObservableOptions): Observable<T> {
92-
!options?.injector && assertInInjectionContext(toObservable);
93-
const injector = options?.injector ?? inject(Injector);
94-
95-
return new Observable<T>((subscriber) => {
96-
let firstVersion: number = -1;
97-
let firstValue: T;
98-
try {
99-
firstValue = untracked(source);
100-
} catch (err) {
101-
// A failure on the first read just errors the observable without
102-
// creating an effect.
103-
subscriber.error(err);
104-
return;
105-
}
106-
// We cache the `version` of the first value. This lets us avoid emitting
107-
// this value a second time during the `effect`.
108-
firstVersion = signalVersion(source);
109-
110-
// Emit the first value synchronously on subscription.
111-
subscriber.next(firstValue);
112-
113-
// Create an effect that will watch the signal for future changes.
114-
let firstEmit = true;
115-
const ref = effect(
116-
() => {
117-
let value: T;
118-
try {
119-
// Read the value (& track it).
120-
value = source();
121-
} catch (err) {
122-
// Errors cause the Observable stream to terminate.
123-
untracked(() => subscriber.error(err));
124-
cleanup(false);
125-
return;
126-
}
127-
128-
// Skip the emit of the value if it hasn't changed since the
129-
// synchronous emit.
130-
if (firstEmit) {
131-
firstEmit = false;
132-
if (signalVersion(source) === firstVersion) {
133-
return;
134-
}
135-
}
136-
137-
untracked(() => subscriber.next(value));
138-
},
139-
{injector, manualCleanup: true},
140-
);
141-
142-
const cleanup = (fromInjector: boolean) => {
143-
ref.destroy();
144-
145-
if (fromInjector) {
146-
// If we're cleaning up because the injector is destroyed, then our
147-
// subscription is still active and we need to complete it.
148-
subscriber.complete();
149-
} else {
150-
// Otherwise, remove the cleanup function. This both prevents the
151-
// complete() event from being produced and allows memory to be
152-
// reclaimed.
153-
removeInjectorCleanupFn();
154-
}
155-
};
156-
157-
const removeInjectorCleanupFn = injector.get(DestroyRef).onDestroy(() => {
158-
// Cleaning up from the `DestroyRef` means the stream is still active, so
159-
// we should emit completion.
160-
cleanup(true);
161-
});
162-
163-
return () => cleanup(false);
164-
});
165-
}
166-
167-
function signalVersion(source: Signal<unknown>): number {
168-
return (source[SIGNAL] as ReactiveNode).version;
169-
}

packages/core/rxjs-interop/test/to_observable_spec.ts

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -176,56 +176,4 @@ describe('toObservable()', () => {
176176
flushEffects();
177177
expect(emits()).toBe(1);
178178
});
179-
180-
describe('synchronous emit', () => {
181-
it('emits synchronously when requested', () => {
182-
const counter = signal(0);
183-
const log: number[] = [];
184-
toObservable(counter, {injector, forceSyncFirstEmit: true}).subscribe((value) =>
185-
log.push(value),
186-
);
187-
188-
expect(log).toEqual([0]);
189-
190-
// Expect no emit after the effect.
191-
flushEffects();
192-
expect(log).toEqual([0]);
193-
194-
counter.set(1);
195-
flushEffects();
196-
expect(log).toEqual([0, 1]);
197-
});
198-
199-
it('emits new values if they happen before the first effect run', () => {
200-
const counter = signal(0);
201-
const log: number[] = [];
202-
toObservable(counter, {injector, forceSyncFirstEmit: true}).subscribe((value) =>
203-
log.push(value),
204-
);
205-
206-
expect(log).toEqual([0]);
207-
counter.set(1);
208-
209-
// Expect new emit after the effect.
210-
flushEffects();
211-
expect(log).toEqual([0, 1]);
212-
});
213-
214-
it('emits new values based on version, not identity', () => {
215-
// Disable value equality checking.
216-
const counter = signal(0, {equal: () => false});
217-
const log: number[] = [];
218-
toObservable(counter, {injector, forceSyncFirstEmit: true}).subscribe((value) =>
219-
log.push(value),
220-
);
221-
222-
expect(log).toEqual([0]);
223-
// Because of the `equal` function, this will be treated as a new value.
224-
counter.set(0);
225-
226-
// Expect new emit after the effect.
227-
flushEffects();
228-
expect(log).toEqual([0, 0]);
229-
});
230-
});
231179
});

0 commit comments

Comments
 (0)