You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
2. If the response has status `200`, call `.json()` to read the JS object.
4
+
If the response has status `200`, call `.json()` to read the JS object.
6
5
7
-
If a `fetch` fails, or the response has non-200 status, we just return `null` in the resulting arrray.
6
+
Otherwise, if a `fetch` fails, or the response has non-200 status, we just return `null` in the resulting arrray.
8
7
9
8
So here's the code:
10
9
@@ -38,4 +37,4 @@ Please note: `.then` call is attached directly to `fetch`, so that when we have
38
37
39
38
If we used `await Promise.all(names.map(name => fetch(...)))`, and call `.json()` on the results, then it would wait for all fetches to respond. By adding `.json()` directly to each `fetch`, we ensure that individual fetches start reading data as JSON without waiting for each other.
40
39
41
-
That's an example of how low-level `Promise` API can still be useful even if we mainly use `async/await`.
40
+
That's an example of how low-level Promise API can still be useful even if we mainly use `async/await`.
Copy file name to clipboardExpand all lines: 5-network/01-fetch/article.md
+44-33Lines changed: 44 additions & 33 deletions
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,7 @@
3
3
4
4
JavaScript can send network requests to the server and load new information whenever is needed.
5
5
6
-
For example, we can:
6
+
For example, we can use a network request to:
7
7
8
8
- Submit an order,
9
9
- Load user information,
@@ -12,11 +12,11 @@ For example, we can:
12
12
13
13
...And all of that without reloading the page!
14
14
15
-
There's an umbrella term "AJAX" (abbreviated <b>A</b>synchronous <b>J</b>avascript <b>A</b>nd <b>X</b>ml) for that. We don't have to use XML though: the term comes from old times, that's that word is there.
15
+
There's an umbrella term "AJAX" (abbreviated <b>A</b>synchronous <b>J</b>avaScript <b>A</b>nd <b>X</b>ML) for network requests from JavaScript. We don't have to use XML though: the term comes from old times, that's that word is there. You may have heard that term already.
16
16
17
17
There are multiple ways to send a network request and get information from the server.
18
18
19
-
The `fetch()` method is modern and versatile, so we'll start with it. It evolved for several years and continues to improve, right now the support is pretty solid among browsers.
19
+
The `fetch()` method is modern and versatile, so we'll start with it. It's not supported by old browsers (can be polyfilled), but very well supported among the new ones.
20
20
21
21
The basic syntax is:
22
22
@@ -27,28 +27,28 @@ let promise = fetch(url, [options])
27
27
-**`url`** -- the URL to access.
28
28
-**`options`** -- optional parameters: method, headers etc.
29
29
30
-
The browser starts the request right away and returns a `promise`.
30
+
The browser starts the request right away and returns a promise that the calling code should use to get the result.
31
31
32
32
Getting a response is usually a two-stage process.
33
33
34
34
**First, the `promise` resolves with an object of the built-in [Response](https://fetch.spec.whatwg.org/#response-class) class as soon as the server responds with headers.**
35
35
36
-
So we can check HTTP status, to see whether it is successful or not, check headers, but don't have the body yet.
36
+
At this stage we can check HTTP status, to see whether it is successful or not, check headers, but don't have the body yet.
37
37
38
-
The promise rejects if the `fetch` was unable to make HTTP-request, e.g. network problems, or there's no such site. HTTP-errors, even such as 404 or 500, are considered a normal flow.
38
+
The promise rejects if the `fetch` was unable to make HTTP-request, e.g. network problems, or there's no such site. Abnormal HTTP-statuses, such as 404 or 500 do not cause an error.
39
39
40
-
We can see them in response properties:
40
+
We can see HTTP-status in response properties:
41
41
42
+
-**`status`** -- HTTP status code, e.g. 200.
42
43
-**`ok`** -- boolean, `true` if the HTTP status code is 200-299.
43
-
-**`status`** -- HTTP status code.
44
44
45
45
For example:
46
46
47
47
```js
48
48
let response =awaitfetch(url);
49
49
50
50
if (response.ok) { // if HTTP-status is 200-299
51
-
// get the response body (see below)
51
+
// get the response body (the method explained below)
52
52
let json =awaitresponse.json();
53
53
} else {
54
54
alert("HTTP-Error: "+response.status);
@@ -59,17 +59,18 @@ if (response.ok) { // if HTTP-status is 200-299
59
59
60
60
`Response` provides multiple promise-based methods to access the body in various formats:
61
61
62
-
-**`response.json()`** -- parse the response as JSON object,
63
-
-**`response.text()`** -- return the response as text,
64
-
-**`response.formData()`** -- return the response as `FormData` object (form/multipart encoding, explained in the [next chapter](info:formdata)),
62
+
-**`response.text()`** -- read the response and return as text,
63
+
-**`response.json()`** -- parse the response as JSON,
64
+
-**`response.formData()`** -- return the response as `FormData` object (explained in the [next chapter](info:formdata)),
65
65
-**`response.blob()`** -- return the response as [Blob](info:blob) (binary data with type),
66
-
-**`response.arrayBuffer()`** -- return the response as [ArrayBuffer](info:arraybuffer-binary-arrays) (pure binary data),
66
+
-**`response.arrayBuffer()`** -- return the response as [ArrayBuffer](info:arraybuffer-binary-arrays) (low-level representaion of binary data),
67
67
- additionally, `response.body` is a [ReadableStream](https://streams.spec.whatwg.org/#rs-class) object, it allows to read the body chunk-by-chunk, we'll see an example later.
68
68
69
69
For instance, let's get a JSON-object with latest commits from GitHub:
70
70
71
71
```js run async
72
-
let response =awaitfetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
72
+
let url ='https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits';
73
+
let response =awaitfetch(url);
73
74
74
75
*!*
75
76
let commits =awaitresponse.json(); // read response body and parse as JSON
To get the text, `await response.text()` instead of `.json()`:
90
+
To get the reponse text, `await response.text()` instead of `.json()`:
91
+
90
92
```js run async
91
93
let response =awaitfetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
92
94
@@ -95,7 +97,7 @@ let text = await response.text(); // read response body as text
95
97
alert(text.slice(0, 80) +'...');
96
98
```
97
99
98
-
As a show-case for reading in binary format, let's fetch and show an image (see chapter [Blob](info:blob) for details about operations on blobs):
100
+
As a show-case for reading in binary format, let's fetch and show a logo image of ["fetch" specification](https://fetch.spec.whatwg.org) (see chapter [Blob](info:blob) for details about operations on `Blob`):
99
101
100
102
```js async run
101
103
let response =awaitfetch('/article/fetch/logo-fetch.svg');
@@ -119,20 +121,20 @@ setTimeout(() => { // hide after three seconds
119
121
```
120
122
121
123
````warn
122
-
We can choose only one body-parsing method.
124
+
We can choose only one body-reading method.
123
125
124
-
If we got the response with `response.text()`, then `response.json()` won't work, as the body content has already been processed.
126
+
If we've already got the response with `response.text()`, then `response.json()` won't work, as the body content has already been processed.
125
127
126
128
```js
127
129
let text = await response.text(); // response body consumed
128
130
let parsed = await response.json(); // fails (already consumed)
129
131
````
130
132
131
-
## Headers
133
+
## Response headers
132
134
133
-
There's a Map-like headers object in `response.headers`.
135
+
The response headers are available in a Map-like headers object in `response.headers`.
134
136
135
-
We can get individual headers or iterate over them:
137
+
It's not exactly a Map, but it has similar methods to get individual headers by name or iterate over them:
136
138
137
139
```js run async
138
140
let response =awaitfetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
@@ -146,12 +148,14 @@ for (let [key, value] of response.headers) {
146
148
}
147
149
```
148
150
149
-
To set a header, we can use the `headers` option, like this:
151
+
## Request headers
152
+
153
+
To set a request header in `fetch`, we can use the `headers` option. It has an object with outgoing headers, like this:
150
154
151
155
```js
152
156
let response =fetch(protectedUrl, {
153
157
headers: {
154
-
Authentication:'abcdef'
158
+
Authentication:'secret'
155
159
}
156
160
});
157
161
```
@@ -186,12 +190,14 @@ These headers ensure proper and safe HTTP, so they are controlled exclusively by
186
190
To make a `POST` request, or a request with another method, we need to use `fetch` options:
187
191
188
192
-**`method`** -- HTTP-method, e.g. `POST`,
189
-
-**`body`** -- one of:
190
-
- a string (e.g. JSON),
193
+
-**`body`** -- the request body, one of:
194
+
- a string (e.g. JSON-encoded),
191
195
-`FormData` object, to submit the data as `form/multipart`,
192
196
-`Blob`/`BufferSource` to send binary data,
193
197
-[URLSearchParams](info:url), to submit the data in `x-www-form-urlencoded` encoding, rarely used.
194
198
199
+
The JSON format is used most of the time.
200
+
195
201
For example, this code submits `user` object as JSON:
196
202
197
203
```js run async
@@ -214,13 +220,15 @@ let result = await response.json();
214
220
alert(result.message);
215
221
```
216
222
217
-
Please note, if the body is a string, then `Content-Type` is set to `text/plain;charset=UTF-8` by default. So we use `headers` option to send `application/json` instead, that's the correct content type for JSON-encoded data.
223
+
Please note, if the request `body` is a string, then `Content-Type` header is set to `text/plain;charset=UTF-8` by default.
224
+
225
+
But, as we're going to send JSON, we use `headers` option to send `application/json` instead, the correct `Content-Type` for JSON-encoded data.
218
226
219
227
## Sending an image
220
228
221
-
We can also submit binary data directly using `Blob` or `BufferSource`.
229
+
We can also submit binary data with `fetch`using `Blob` or `BufferSource` objects.
222
230
223
-
For example, here's a `<canvas>` where we can draw by moving a mouse. A click on the "submit" button sends the image to server:
231
+
In this example, there's a `<canvas>` where we can draw by moving a mouse over it. A click on the "submit" button sends the image to server:
224
232
225
233
```html run autorun height="90"
226
234
<bodystyle="margin:0">
@@ -241,6 +249,8 @@ For example, here's a `<canvas>` where we can draw by moving a mouse. A click on
241
249
method:'POST',
242
250
body: blob
243
251
});
252
+
253
+
// the server responds with confirmation and the image size
244
254
let result =awaitresponse.json();
245
255
alert(result.message);
246
256
}
@@ -249,7 +259,7 @@ For example, here's a `<canvas>` where we can draw by moving a mouse. A click on
249
259
</body>
250
260
```
251
261
252
-
Here we also didn't need to set `Content-Type` manually, because a `Blob` object has a built-in type (here `image/png`, as generated by `toBlob`).
262
+
Please note, here we don't set `Content-Type`header manually, because a `Blob` object has a built-in type (here `image/png`, as generated by `toBlob`). For `Blob` objects that type becomes the value of `Content-Type`.
253
263
254
264
The `submit()` function can be rewritten without `async/await` like this:
255
265
@@ -275,7 +285,8 @@ let response = await fetch(url, options); // resolves with response headers
275
285
let result =awaitresponse.json(); // read body as json
276
286
```
277
287
278
-
Or, promise-style:
288
+
Or, without `await`:
289
+
279
290
```js
280
291
fetch(url, options)
281
292
.then(response=>response.json())
@@ -288,15 +299,15 @@ Response properties:
288
299
-`response.headers` -- Map-like object with HTTP headers.
289
300
290
301
Methods to get response body:
291
-
-**`response.json()`** -- parse the response as JSON object,
292
302
-**`response.text()`** -- return the response as text,
303
+
-**`response.json()`** -- parse the response as JSON object,
293
304
-**`response.formData()`** -- return the response as `FormData` object (form/multipart encoding, see the next chapter),
294
305
-**`response.blob()`** -- return the response as [Blob](info:blob) (binary data with type),
295
-
-**`response.arrayBuffer()`** -- return the response as [ArrayBuffer](info:arraybuffer-binary-arrays) (pure binary data),
306
+
-**`response.arrayBuffer()`** -- return the response as [ArrayBuffer](info:arraybuffer-binary-arrays) (low-level binary data),
296
307
297
308
Fetch options so far:
298
309
-`method` -- HTTP-method,
299
310
-`headers` -- an object with request headers (not any header is allowed),
300
-
-`body` -- `string`, `FormData`, `BufferSource`, `Blob` or `UrlSearchParams` object to send.
311
+
-`body` -- the data to send (request body) as `string`, `FormData`, `BufferSource`, `Blob` or `UrlSearchParams` object.
301
312
302
313
In the next chapters we'll see more options and use cases of `fetch`.
0 commit comments