admin管理员组

文章数量:1278880

I have been defining resource as follows:

resource: ResourceRef<any> = resource<ResourceRequest | undefined, any>({
  request: (): ResourceRequest | undefined => {
    return {
      id: this.id(),
    };
  },
  loader: ({ request: { id }, abortSignal }) => {
    return fetch(`/${id}`).then(
      (res: any) => res.json()
    );
  },
});

Seems sufficient to achieve what I want, but I see this pattern in blogs and youtube where they add the AbortSignal to the fetch request.

loader: ({ request: { id }, abortSignal }) => {
  return fetch(`/${id}`, {
    signal: abortSignal,
  }).then((res: any) => res.json());
},

What is the necessity for this?

Below is my minimal reproducible code with working stackblitz.

TS:

id = signal(1);
rs = ResourceStatus;
http = inject(HttpClient);
resourceControl = signal(true);
resource: ResourceRef<any> = resource<ResourceRequest | undefined, any>({
  request: (): ResourceRequest | undefined => {
    return {
      id: this.id(),
    };
  },
  loader: ({ request: { id }, abortSignal }) => {
    return fetch(`/${id}`).then(
      (res: any) => res.json()
    );
  },
});

HTML:

<div>
  <div>
    Resource Request triggers:
  </div>
  <div>
    <input [(ngModel)]="id" type="number"/>
  </div>
</div>
<div>
  @if(![rs.Loading, rs.Reloading].includes(resource.status())) {
    {{resource.value() | json}}
  } @else{
    Loading...
  }
</div>

Stackblitz Demo

I have been defining resource as follows:

resource: ResourceRef<any> = resource<ResourceRequest | undefined, any>({
  request: (): ResourceRequest | undefined => {
    return {
      id: this.id(),
    };
  },
  loader: ({ request: { id }, abortSignal }) => {
    return fetch(`https://jsonplaceholder.typicode/todos/${id}`).then(
      (res: any) => res.json()
    );
  },
});

Seems sufficient to achieve what I want, but I see this pattern in blogs and youtube where they add the AbortSignal to the fetch request.

loader: ({ request: { id }, abortSignal }) => {
  return fetch(`https://jsonplaceholder.typicode/todos/${id}`, {
    signal: abortSignal,
  }).then((res: any) => res.json());
},

What is the necessity for this?

Below is my minimal reproducible code with working stackblitz.

TS:

id = signal(1);
rs = ResourceStatus;
http = inject(HttpClient);
resourceControl = signal(true);
resource: ResourceRef<any> = resource<ResourceRequest | undefined, any>({
  request: (): ResourceRequest | undefined => {
    return {
      id: this.id(),
    };
  },
  loader: ({ request: { id }, abortSignal }) => {
    return fetch(`https://jsonplaceholder.typicode/todos/${id}`).then(
      (res: any) => res.json()
    );
  },
});

HTML:

<div>
  <div>
    Resource Request triggers:
  </div>
  <div>
    <input [(ngModel)]="id" type="number"/>
  </div>
</div>
<div>
  @if(![rs.Loading, rs.Reloading].includes(resource.status())) {
    {{resource.value() | json}}
  } @else{
    Loading...
  }
</div>

Stackblitz Demo

Share Improve this question edited Feb 24 at 10:16 Naren Murali asked Feb 24 at 4:03 Naren MuraliNaren Murali 58.2k5 gold badges44 silver badges76 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

From the documentation:

resource will cancel in-progress loads via the AbortSignal when destroyed or when a new request object becomes available, which could prematurely abort mutations.

The syntax to configure the AbortController is as follows:

resource: ResourceRef<any> = resource<ResourceRequest | undefined, any>({
  ...
  loader: ({ request: { id }, abortSignal }) => {
    return fetch(`https://jsonplaceholder.typicode/todos/${id}`, {
      signal: abortSignal
    }).then((res: any) => res.json();
  },
});

The signal property from RequestInit Object - MDN Docs

An AbortSignal. If this option is set, the request can be canceled by calling abort() on the corresponding AbortController.

So providing the AbortController will do two things:

  1. When a new request object arrives the previous still running requests are aborted (cancelled) - thus saving network resources.

  2. When the resource is itself destroyed the still running requests are aborted.


In the below screenshots you can see the difference between using it and not using it:

Without Abort Controller:

With Abort Controller:

For rxResource this is not a prerequisite, since it automatically performs this action, similar to the switchMap behavior of rxjs (does not use switchMap though).

Full Code:

import {
  Component,
  inject,
  ResourceRef,
  ResourceStatus,
  signal,
  resource,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { rxResource } from '@angular/core/rxjs-interop';
import { HttpClient, provideHttpClient } from '@angular/common/http';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

export interface ResourceRequest {
  id: number;
}

@Component({
  selector: 'app-root',
  imports: [CommonModule, FormsModule],
  template: `
    <div>
      <div>
        Resource Request triggers:
      </div>
      <div>
        <input [(ngModel)]="id" type="number"/>
      </div>
    </div>
    <div>
      @if(![rs.Loading, rs.Reloading].includes(resource.status())) {
        {{resource.value() | json}}
      } @else{
        Loading...
      }
    </div>
  `,
})
export class App {
  id = signal(1);
  rs = ResourceStatus;
  http = inject(HttpClient);
  resourceControl = signal(true);
  resource: ResourceRef<any> = resource<ResourceRequest | undefined, any>({
    request: (): ResourceRequest | undefined => {
      return {
        id: this.id(),
      };
    },
    loader: ({ request: { id }, abortSignal }) => {
      return fetch(`https://jsonplaceholder.typicode/todos/${id}`, {
        signal: abortSignal,
      }).then((res: any) => res.json());
    },
  });
}

bootstrapApplication(App, {
  providers: [provideHttpClient()],
});

Stackblitz Demo

本文标签: typescriptWhy do I need AbortSignal when using the resource API of angular What is it39s useStack Overflow