Repository: angular/angular
File: packages/core/src/resource/resource.ts (TypeScript)

Code before:
   */
  private readonly state: WritableSignal<ResourceState<T>>;

  /**
   * Combines the current request with a reload counter which allows the resource to be reloaded on
   * imperative command.
   */
  protected readonly extRequest: WritableSignal<WrappedRequest>;
  private readonly effectRef: EffectRef;

  private pendingController: AbortController | undefined;
  private resolvePendingTask: (() => void) | undefined = undefined;
  private destroyed = false;
  private unregisterOnDestroy: () => void;

  override readonly status: Signal<ResourceStatus>;
  override readonly error: Signal<Error | undefined>;

  constructor(
    request: () => R,
    private readonly loaderFn: ResourceStreamingLoader<T, R>,
    defaultValue: T,
    private readonly equal: ValueEqualityFn<T> | undefined,
    private readonly debugName: string | undefined,
    injector: Injector,
    private readonly initialStream?: Signal<ResourceStreamItem<T>>,
  ) {
    super(
      // Feed a computed signal for the value to `BaseWritableResource`, which will upgrade it to a
      // `WritableSignal` that delegates to `ResourceImpl.set`.
      computed(
        () => {
          const streamValue = this.state().stream?.();

          if (!streamValue) {
            return defaultValue;
          }

          // Prevents `hasValue()` from throwing an error when a reload happened in the error state
          if (this.state().status === 'loading' && this.error()) {
            return defaultValue;
          }

          if (!isResolved(streamValue)) {
            throw new ResourceValueError(this.error()!);
          }

          return streamValue.value;
        },
        {equal, ...(ngDevMode ? createDebugNameObject(debugName, 'value') : undefined)},
      ),

Review comment (performance):
Minor nit: we should clear this after we evaluate for the first time, to not leak the memory of the cached item.

Code after:
   */
  private readonly state: WritableSignal<ResourceState<T>>;

  /**
   * Combines the current request with a reload counter which allows the resource to be reloaded on
   * imperative command.
   */
  protected readonly extRequest: WritableSignal<WrappedRequest>;
  private readonly effectRef: EffectRef;

  private pendingController: AbortController | undefined;
  private resolvePendingTask: (() => void) | undefined = undefined;
  private destroyed = false;
  private unregisterOnDestroy: () => void;

  override readonly status: Signal<ResourceStatus>;
  override readonly error: Signal<Error | undefined>;

  constructor(
    request: () => R,
    private readonly loaderFn: ResourceStreamingLoader<T, R>,
    defaultValue: T,
    private readonly equal: ValueEqualityFn<T> | undefined,
    private readonly debugName: string | undefined,
    injector: Injector,
    getInitialStream?: (request: R) => Signal<ResourceStreamItem<T>> | undefined,
  ) {
    super(
      // Feed a computed signal for the value to `BaseWritableResource`, which will upgrade it to a
      // `WritableSignal` that delegates to `ResourceImpl.set`.
      computed(
        () => {
          const streamValue = this.state().stream?.();

          if (!streamValue) {
            return defaultValue;
          }

          // Prevents `hasValue()` from throwing an error when a reload happened in the error state
          if (this.state().status === 'loading' && this.error()) {
            return defaultValue;
          }

          if (!isResolved(streamValue)) {
            throw new ResourceValueError(this.error()!);
          }

          return streamValue.value;
        },
        {equal, ...(ngDevMode ? createDebugNameObject(debugName, 'value') : undefined)},
      ),