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 authored 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
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,7 @@ const defaultInternals: Options['_internals'] = {
},
setHost: true,
maxHeaderSize: undefined,
signal: undefined,
enableUnixSockets: true,
};

Expand Down Expand Up @@ -1489,6 +1490,38 @@ export default class Options {
}
}

/**
You can abort the `request` using [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
*Requires Node.js 16 or later.*
@example
```
import got from 'got';
const abortController = new AbortController();
const request = got('https://httpbin.org/anything', {
signal: abortController.signal
});
setTimeout(() => {
abortController.abort();
}, 100);
```
*/
// TODO: Replace `any` with `AbortSignal` when targeting Node 16.
get signal(): any | undefined {
return this._internals.signal;
}

// TODO: Replace `any` with `AbortSignal` when targeting Node 16.
set signal(value: any | undefined) {
assert.object(value);

this._internals.signal = value;
}

/**
Ignore invalid cookies instead of throwing an error.
Only useful when the `cookieJar` option has been set. Not recommended.
Expand Down Expand Up @@ -2488,5 +2521,6 @@ export default class Options {
Object.freeze(options.retry.methods);
Object.freeze(options.retry.statusCodes);
Object.freeze(options.context);
Object.freeze(options.signal);
}
}
Loading

0 comments on commit 6a6d2a9

Please sign in to comment.