Skip to content

Commit

Permalink
feat: add asyn iterable section in doc
Browse files Browse the repository at this point in the history
Issue: nodejs#991

Added a description and an exmaple of async iterables in the doc
  • Loading branch information
abskrj committed Feb 3, 2022
1 parent 6dc06f0 commit 9b5addc
Showing 1 changed file with 135 additions and 114 deletions.
249 changes: 135 additions & 114 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
A HTTP/1.1 client, written from scratch for Node.js.

> Undici means eleven in Italian. 1.1 -> 11 -> Eleven -> Undici.
It is also a Stranger Things reference.
> It is also a Stranger Things reference.
Have a question about using Undici? Open a [Q&A Discussion](https://github.com/nodejs/undici/discussions/new) or join our official OpenJS [Slack](https://openjs-foundation.slack.com/archives/C01QF9Q31QD) channel.

Expand All @@ -23,64 +23,58 @@ The benchmarks below have the [simd](https://github.com/WebAssembly/simd) featur

### Connections 1

| Tests | Samples | Result | Tolerance | Difference with slowest |
|---------------------|---------|---------------|-----------|-------------------------|
| http - no keepalive | 15 | 4.63 req/sec | ± 2.77 % | - |
| http - keepalive | 10 | 4.81 req/sec | ± 2.16 % | + 3.94 % |
| undici - stream | 25 | 62.22 req/sec | ± 2.67 % | + 1244.58 % |
| undici - dispatch | 15 | 64.33 req/sec | ± 2.47 % | + 1290.24 % |
| undici - request | 15 | 66.08 req/sec | ± 2.48 % | + 1327.88 % |
| undici - pipeline | 10 | 66.13 req/sec | ± 1.39 % | + 1329.08 % |
| Tests | Samples | Result | Tolerance | Difference with slowest |
| ------------------- | ------- | ------------- | --------- | ----------------------- |
| http - no keepalive | 15 | 4.63 req/sec | ± 2.77 % | - |
| http - keepalive | 10 | 4.81 req/sec | ± 2.16 % | + 3.94 % |
| undici - stream | 25 | 62.22 req/sec | ± 2.67 % | + 1244.58 % |
| undici - dispatch | 15 | 64.33 req/sec | ± 2.47 % | + 1290.24 % |
| undici - request | 15 | 66.08 req/sec | ± 2.48 % | + 1327.88 % |
| undici - pipeline | 10 | 66.13 req/sec | ± 1.39 % | + 1329.08 % |

### Connections 50

| Tests | Samples | Result | Tolerance | Difference with slowest |
|---------------------|---------|------------------|-----------|-------------------------|
| http - no keepalive | 50 | 3546.49 req/sec | ± 2.90 % | - |
| http - keepalive | 15 | 5692.67 req/sec | ± 2.48 % | + 60.52 % |
| undici - pipeline | 25 | 8478.71 req/sec | ± 2.62 % | + 139.07 % |
| undici - request | 20 | 9766.66 req/sec | ± 2.79 % | + 175.39 % |
| undici - stream | 15 | 10109.74 req/sec | ± 2.94 % | + 185.06 % |
| undici - dispatch | 25 | 10949.73 req/sec | ± 2.54 % | + 208.75 % |
| Tests | Samples | Result | Tolerance | Difference with slowest |
| ------------------- | ------- | ---------------- | --------- | ----------------------- |
| http - no keepalive | 50 | 3546.49 req/sec | ± 2.90 % | - |
| http - keepalive | 15 | 5692.67 req/sec | ± 2.48 % | + 60.52 % |
| undici - pipeline | 25 | 8478.71 req/sec | ± 2.62 % | + 139.07 % |
| undici - request | 20 | 9766.66 req/sec | ± 2.79 % | + 175.39 % |
| undici - stream | 15 | 10109.74 req/sec | ± 2.94 % | + 185.06 % |
| undici - dispatch | 25 | 10949.73 req/sec | ± 2.54 % | + 208.75 % |

## Quick Start

```js
import { request } from 'undici'
import { request } from "undici";

const {
statusCode,
headers,
trailers,
body
} = await request('http://localhost:3000/foo')
const { statusCode, headers, trailers, body } = await request(
"http://localhost:3000/foo"
);

console.log('response received', statusCode)
console.log('headers', headers)
console.log("response received", statusCode);
console.log("headers", headers);

for await (const data of body) {
console.log('data', data)
console.log("data", data);
}

console.log('trailers', trailers)
console.log("trailers", trailers);
```

Using [the body mixin from the Fetch Standard](https://fetch.spec.whatwg.org/#body-mixin).

```js
import { request } from 'undici'

const {
statusCode,
headers,
trailers,
body
} = await request('http://localhost:3000/foo')

console.log('response received', statusCode)
console.log('headers', headers)
console.log('data', await body.json())
console.log('trailers', trailers)
import { request } from "undici";

const { statusCode, headers, trailers, body } = await request(
"http://localhost:3000/foo"
);

console.log("response received", statusCode);
console.log("headers", headers);
console.log("data", await body.json());
console.log("trailers", trailers);
```

## Common API Methods
Expand All @@ -91,11 +85,11 @@ This section documents our most commonly used API methods. Additional APIs are d

Arguments:

* **url** `string | URL | UrlObject`
* **options** [`RequestOptions`](./docs/api/Dispatcher.md#parameter-requestoptions)
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
* **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
* **maxRedirections** `Integer` - Default: `0`
- **url** `string | URL | UrlObject`
- **options** [`RequestOptions`](./docs/api/Dispatcher.md#parameter-requestoptions)
- **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
- **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
- **maxRedirections** `Integer` - Default: `0`

Returns a promise with the result of the `Dispatcher.request` method.

Expand All @@ -107,12 +101,12 @@ See [Dispatcher.request](./docs/api/Dispatcher.md#dispatcherrequestoptions-callb

Arguments:

* **url** `string | URL | UrlObject`
* **options** [`StreamOptions`](./docs/api/Dispatcher.md#parameter-streamoptions)
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
* **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
* **maxRedirections** `Integer` - Default: `0`
* **factory** `Dispatcher.stream.factory`
- **url** `string | URL | UrlObject`
- **options** [`StreamOptions`](./docs/api/Dispatcher.md#parameter-streamoptions)
- **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
- **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
- **maxRedirections** `Integer` - Default: `0`
- **factory** `Dispatcher.stream.factory`

Returns a promise with the result of the `Dispatcher.stream` method.

Expand All @@ -124,12 +118,12 @@ See [Dispatcher.stream](docs/api/Dispatcher.md#dispatcherstreamoptions-factory-c

Arguments:

* **url** `string | URL | UrlObject`
* **options** [`PipelineOptions`](docs/api/Dispatcher.md#parameter-pipelineoptions)
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
* **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
* **maxRedirections** `Integer` - Default: `0`
* **handler** `Dispatcher.pipeline.handler`
- **url** `string | URL | UrlObject`
- **options** [`PipelineOptions`](docs/api/Dispatcher.md#parameter-pipelineoptions)
- **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
- **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
- **maxRedirections** `Integer` - Default: `0`
- **handler** `Dispatcher.pipeline.handler`

Returns: `stream.Duplex`

Expand All @@ -143,11 +137,11 @@ Starts two-way communications with the requested resource using [HTTP CONNECT](h

Arguments:

* **url** `string | URL | UrlObject`
* **options** [`ConnectOptions`](docs/api/Dispatcher.md#parameter-connectoptions)
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
* **maxRedirections** `Integer` - Default: `0`
* **callback** `(err: Error | null, data: ConnectData | null) => void` (optional)
- **url** `string | URL | UrlObject`
- **options** [`ConnectOptions`](docs/api/Dispatcher.md#parameter-connectoptions)
- **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
- **maxRedirections** `Integer` - Default: `0`
- **callback** `(err: Error | null, data: ConnectData | null) => void` (optional)

Returns a promise with the result of the `Dispatcher.connect` method.

Expand All @@ -159,8 +153,8 @@ See [Dispatcher.connect](docs/api/Dispatcher.md#dispatcherconnectoptions-callbac

Implements [fetch](https://fetch.spec.whatwg.org/#fetch-method).

* https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
* https://fetch.spec.whatwg.org/#fetch-method
- https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
- https://fetch.spec.whatwg.org/#fetch-method

Only supported on Node 16.5+.

Expand All @@ -171,28 +165,57 @@ Help us improve the test coverage by following instructions at [nodejs/undici/#9
Basic usage example:

```js
import {fetch} from 'undici';
import { fetch } from "undici";

async function fetchJson() {
const res = await fetch("https://example.com");
const json = await res.json();
console.log(json);
}
```

#### `request.body`

async function fetchJson() {
const res = await fetch('https://example.com')
const json = await res.json()
console.log(json);
}
A body can be any of the following type:

- ArrayBuffer
- ArrayBufferView
- AsyncIterables
- Blob
- String
- URLSearchParams
- FormData

In this implementation of fetch, AsyncIterables if added. It is not present in the [Fetch Standard.](https://fetch.spec.whatwg.org)

```js
import { fetch } from "undici";

const data = {
async *[Symbol.asyncIterator]() {
yield "hello";
yield "world";
},
};

(async () => {
await fetch("https://example.com", { body: data });
})();
```

#### `response.body`

Nodejs has two kinds of streams: [web streams](https://nodejs.org/dist/latest-v16.x/docs/api/webstreams.html) which follow the API of the WHATWG web standard found in browsers, and an older Node-specific [streams API](https://nodejs.org/api/stream.html). `response.body` returns a readable web stream. If you would prefer to work with a Node stream you can convert a web stream using `.fromWeb()`.

```js
import {fetch} from 'undici';
import {Readable} from 'node:stream';

async function fetchStream() {
const response = await fetch('https://example.com')
const readableWebStream = response.body;
const readableNodeStream = Readable.fromWeb(readableWebStream);
}
import { fetch } from "undici";
import { Readable } from "node:stream";

async function fetchStream() {
const response = await fetch("https://example.com");
const readableWebStream = response.body;
const readableNodeStream = Readable.fromWeb(readableWebStream);
}
```

#### Specification Compliance
Expand All @@ -202,7 +225,7 @@ not support or does not fully implement.

##### Garbage Collection

* https://fetch.spec.whatwg.org/#garbage-collection
- https://fetch.spec.whatwg.org/#garbage-collection

The [Fetch Standard](https://fetch.spec.whatwg.org) allows users to skip consuming the response body by relying on
[garbage collection](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management#garbage_collection) to release connection resources. Undici does not do the same. Therefore, it is important to always either consume or cancel the response body.
Expand All @@ -215,17 +238,15 @@ stalls or deadlocks when running out of connections.

```js
// Do
const headers = await fetch(url)
.then(async res => {
for await (const chunk of res.body) {
// force consumption of body
}
return res.headers
})
const headers = await fetch(url).then(async (res) => {
for await (const chunk of res.body) {
// force consumption of body
}
return res.headers;
});

// Do not
const headers = await fetch(url)
.then(res => res.headers)
const headers = await fetch(url).then((res) => res.headers);
```

### `undici.upgrade([url, options]): Promise`
Expand All @@ -234,11 +255,11 @@ Upgrade to a different protocol. See [MDN - HTTP - Protocol upgrade mechanism](h

Arguments:

* **url** `string | URL | UrlObject`
* **options** [`UpgradeOptions`](docs/api/Dispatcher.md#parameter-upgradeoptions)
* **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
* **maxRedirections** `Integer` - Default: `0`
* **callback** `(error: Error | null, data: UpgradeData) => void` (optional)
- **url** `string | URL | UrlObject`
- **options** [`UpgradeOptions`](docs/api/Dispatcher.md#parameter-upgradeoptions)
- **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
- **maxRedirections** `Integer` - Default: `0`
- **callback** `(error: Error | null, data: UpgradeData) => void` (optional)

Returns a promise with the result of the `Dispatcher.upgrade` method.

Expand All @@ -248,7 +269,7 @@ See [Dispatcher.upgrade](docs/api/Dispatcher.md#dispatcherupgradeoptions-callbac

### `undici.setGlobalDispatcher(dispatcher)`

* dispatcher `Dispatcher`
- dispatcher `Dispatcher`

Sets the global dispatcher used by Common API Methods.

Expand All @@ -260,13 +281,13 @@ Returns: `Dispatcher`

### `UrlObject`

* **port** `string | number` (optional)
* **path** `string` (optional)
* **pathname** `string` (optional)
* **hostname** `string` (optional)
* **origin** `string` (optional)
* **protocol** `string` (optional)
* **search** `string` (optional)
- **port** `string | number` (optional)
- **path** `string` (optional)
- **pathname** `string` (optional)
- **hostname** `string` (optional)
- **origin** `string` (optional)
- **protocol** `string` (optional)
- **search** `string` (optional)

## Specification Compliance

Expand All @@ -276,7 +297,7 @@ not support or does not fully implement.
### Expect

Undici does not support the `Expect` request header field. The request
body is always immediately sent and the `100 Continue` response will be
body is always immediately sent and the `100 Continue` response will be
ignored.

Refs: https://tools.ietf.org/html/rfc7231#section-5.1.1
Expand All @@ -298,23 +319,23 @@ the prior pipeline and instead error the corresponding callback/promise/stream.
Undici will abort all running requests in the pipeline when any of them are
aborted.

* Refs: https://tools.ietf.org/html/rfc2616#section-8.1.2.2
* Refs: https://tools.ietf.org/html/rfc7230#section-6.3.2
- Refs: https://tools.ietf.org/html/rfc2616#section-8.1.2.2
- Refs: https://tools.ietf.org/html/rfc7230#section-6.3.2

## Collaborators

* [__Daniele Belardi__](https://github.com/dnlup), <https://www.npmjs.com/~dnlup>
* [__Ethan Arrowood__](https://github.com/ethan-arrowood), <https://www.npmjs.com/~ethan_arrowood>
* [__Matteo Collina__](https://github.com/mcollina), <https://www.npmjs.com/~matteo.collina>
* [__Robert Nagy__](https://github.com/ronag), <https://www.npmjs.com/~ronag>
* [__Szymon Marczak__](https://github.com/szmarczak), <https://www.npmjs.com/~szmarczak>
* [__Tomas Della Vedova__](https://github.com/delvedor), <https://www.npmjs.com/~delvedor>
- [**Daniele Belardi**](https://github.com/dnlup), <https://www.npmjs.com/~dnlup>
- [**Ethan Arrowood**](https://github.com/ethan-arrowood), <https://www.npmjs.com/~ethan_arrowood>
- [**Matteo Collina**](https://github.com/mcollina), <https://www.npmjs.com/~matteo.collina>
- [**Robert Nagy**](https://github.com/ronag), <https://www.npmjs.com/~ronag>
- [**Szymon Marczak**](https://github.com/szmarczak), <https://www.npmjs.com/~szmarczak>
- [**Tomas Della Vedova**](https://github.com/delvedor), <https://www.npmjs.com/~delvedor>

### Releasers

* [__Ethan Arrowood__](https://github.com/ethan-arrowood), <https://www.npmjs.com/~ethan_arrowood>
* [__Matteo Collina__](https://github.com/mcollina), <https://www.npmjs.com/~matteo.collina>
* [__Robert Nagy__](https://github.com/ronag), <https://www.npmjs.com/~ronag>
- [**Ethan Arrowood**](https://github.com/ethan-arrowood), <https://www.npmjs.com/~ethan_arrowood>
- [**Matteo Collina**](https://github.com/mcollina), <https://www.npmjs.com/~matteo.collina>
- [**Robert Nagy**](https://github.com/ronag), <https://www.npmjs.com/~ronag>

## License

Expand Down

0 comments on commit 9b5addc

Please sign in to comment.