(opts: RxResourceOptions<T, R>)
| 51 | */ |
| 52 | export function rxResource<T, R>(opts: RxResourceOptions<T, R>): ResourceRef<T | undefined>; |
| 53 | export function rxResource<T, R>(opts: RxResourceOptions<T, R>): ResourceRef<T | undefined> { |
| 54 | if (ngDevMode && !opts?.injector) { |
| 55 | assertInInjectionContext(rxResource); |
| 56 | } |
| 57 | return resource<T, R>({ |
| 58 | ...opts, |
| 59 | loader: undefined, |
| 60 | stream: (params) => { |
| 61 | let sub: Subscription | undefined; |
| 62 | |
| 63 | // `abort` can fire synchronously while the subscription is not initialized yet. |
| 64 | // Use this flag to unsubscribe immediately once `sub` exists. |
| 65 | let aborted = false; |
| 66 | |
| 67 | // Start off stream as undefined. |
| 68 | const stream = signal<ResourceStreamItem<T>>({value: undefined as T}); |
| 69 | const {resolve, promise} = promiseWithResolvers<Signal<ResourceStreamItem<T>>>(); |
| 70 | let hasResolved = false; |
| 71 | |
| 72 | function resolveOnce(): void { |
| 73 | if (!hasResolved) { |
| 74 | hasResolved = true; |
| 75 | resolve(stream); |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | // Track the abort listener so it can be removed if the Observable completes (as a memory |
| 80 | // optimization). |
| 81 | const onAbort = () => { |
| 82 | aborted = true; |
| 83 | sub?.unsubscribe(); |
| 84 | // Remove the listener immediately since unsubscribe won't trigger the subscription's |
| 85 | // error/complete handlers. This ensures the promise resolves and PendingTask is released. |
| 86 | params.abortSignal.removeEventListener('abort', onAbort); |
| 87 | // Resolve the promise with the current stream state if it hasn't been resolved yet. |
| 88 | // This ensures the PendingTask created for this request is released. |
| 89 | resolveOnce(); |
| 90 | }; |
| 91 | params.abortSignal.addEventListener('abort', onAbort); |
| 92 | |
| 93 | function send(value: ResourceStreamItem<T>): void { |
| 94 | stream.set(value); |
| 95 | resolveOnce(); |
| 96 | } |
| 97 | |
| 98 | const streamFn = opts.stream; |
| 99 | if (streamFn === undefined) { |
| 100 | throw new ɵRuntimeError( |
| 101 | ɵRuntimeErrorCode.MUST_PROVIDE_STREAM_OPTION, |
| 102 | ngDevMode && `Must provide \`stream\` option.`, |
| 103 | ); |
| 104 | } |
| 105 | |
| 106 | sub = streamFn(params).subscribe({ |
| 107 | next: (value) => send({value}), |
| 108 | error: (error: unknown) => { |
| 109 | send({error: encapsulateResourceError(error)}); |
| 110 | params.abortSignal.removeEventListener('abort', onAbort); |
no test coverage detected
searching dependent graphs…