Skip to content

Commit

Permalink
Support AbortController (#2020)
Browse files Browse the repository at this point in the history
Co-authored-by: Szymon Marczak <36894700+szmarczak@users.noreply.github.com>
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
3 people committed Jul 24, 2022
1 parent 3207061 commit 6a6d2a9
Show file tree
Hide file tree
Showing 6 changed files with 356 additions and 0 deletions.
22 changes: 22 additions & 0 deletions documentation/2-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,28 @@ await got('https://httpbin.org/anything');
#### **Note:**
> - If you're passing an absolute URL as `url`, you need to set `prefixUrl` to an empty string.
### `signal`

**Type: [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)**

You can abort the `request` using [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).

*Requires Node.js 16 or later.*

```js
import got from 'got';

const abortController = new AbortController();

const request = got('https://httpbin.org/anything', {
signal: abortController.signal
});

setTimeout(() => {
abortController.abort();
}, 100);
```

### `method`

**Type: `string`**\
Expand Down
6 changes: 6 additions & 0 deletions documentation/8-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,9 @@ When the request is aborted with `promise.cancel()`.
**Code: `ERR_RETRYING`**

Always triggers a new retry when thrown.

### `AbortError`

**Code: `ERR_ABORTED`**

When the request is aborted with [AbortController.abort()](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort).
11 changes: 11 additions & 0 deletions source/core/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,14 @@ export class RetryError extends RequestError {
this.code = 'ERR_RETRYING';
}
}

/**
An error to be thrown when the request is aborted by AbortController.
*/
export class AbortError extends RequestError {
constructor(request: Request) {
super('This operation was aborted.', {}, request);
this.code = 'ERR_ABORTED';
this.name = 'AbortError';
}
}
9 changes: 9 additions & 0 deletions source/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
TimeoutError,
UploadError,
CacheError,
AbortError,
} from './errors.js';
import type {PlainResponse} from './response.js';
import type {PromiseCookieJar, NativeRequestOptions, RetryOptions} from './options.js';
Expand Down Expand Up @@ -241,6 +242,14 @@ export default class Request extends Duplex implements RequestEvents<Request> {
return;
}

if (this.options.signal?.aborted) {
this.destroy(new AbortError(this));
}

this.options.signal?.addEventListener('abort', () => {
this.destroy(new AbortError(this));
});

// Important! If you replace `body` in a handler with another stream, make sure it's readable first.
// The below is run only once.
const {body} = this.options;
Expand Down
34 changes: 34 additions & 0 deletions source/core/options.ts