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
{{ message }}
This repository was archived by the owner on Aug 10, 2022. It is now read-only.
Copy file name to clipboardExpand all lines: src/content/en/fundamentals/getting-started/primers/async-functions.md
+80-27Lines changed: 80 additions & 27 deletions
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
project_path: /web/_project.yaml
2
2
book_path: /web/fundamentals/_book.yaml
3
-
description: TODO
3
+
description: Async functions allow you to write promise-based code as if it were synchronous
4
4
5
5
{# wf_published_on: 2016-10-07 #}
6
6
{# wf_updated_on: 2016-10-07 #}
@@ -9,7 +9,10 @@ description: TODO
9
9
10
10
{% include "web/_shared/contributors/jakearchibald.html" %}
11
11
12
-
Async functions are enabled by default in Chrome 55 and they're quite frankly marvelous. They allow you to write promise-based code as if it were synchronous, but without blocking the main thread. They make your asynchronous code less "clever" and more readable.
12
+
Async functions are enabled by default in Chrome 55 and they're quite frankly
13
+
marvelous. They allow you to write promise-based code as if it were synchronous,
14
+
but without blocking the main thread. They make your asynchronous code less
15
+
"clever" and more readable.
13
16
14
17
Async functions look like this:
15
18
@@ -22,11 +25,16 @@ Async functions look like this:
22
25
}
23
26
}
24
27
25
-
If you use the `async` keyword before a function definition, you can then use `await` within the function. When you `await` a promise, the function is paused until the promise settles. If the promise fulfills, you get the value back. If the promise rejects, the rejected value is thrown.
28
+
If you use the `async` keyword before a function definition, you can then use
29
+
`await` within the function. When you `await` a promise, the function is paused
30
+
until the promise settles. If the promise fulfills, you get the value back. If
31
+
the promise rejects, the rejected value is thrown.
26
32
27
-
Note: If you're unfamiliar with promises & promise terminology, check out [our promises guide](/web/fundamentals/getting-started/primers/promises).
33
+
Note: If you're unfamiliar with promises & promise terminology, check out [our
Calling an async function returns a promise for whatever the function returns or throws. So with:
36
+
Calling an async function returns a promise for whatever the function returns or
37
+
throws. So with:
30
38
31
39
// wait ms milliseconds
32
40
function wait(ms) {
@@ -47,11 +55,14 @@ Calling an async function returns a promise for whatever the function returns or
47
55
48
56
…calling `foo()` returns a promise that *rejects* with `Error('bar')`.
49
57
50
-
Note: You can only use `await` directly inside an async function. There's some discussion to allow top-level `await` in modules, but it's [somewhat controversial](https://gist.github.com/Rich-Harris/0b6f317657f5167663b493c722647221).
58
+
Note: You can only use `await` directly inside an async function. There's some
59
+
discussion to allow top-level `await` in modules, but it's [somewhat
Say we wanted to fetch a URL and log the response as text. Here's how it looks using promises:
64
+
Say we wanted to fetch a URL and log the response as text. Here's how it looks
65
+
using promises:
55
66
56
67
function logFetch(url) {
57
68
return fetch(url)
@@ -75,11 +86,13 @@ And here's the same thing using async functions:
75
86
}
76
87
}
77
88
78
-
It's the same number of lines, but all the callbacks are gone. This makes it way easier to read, especially for those less familiar with promises.
89
+
It's the same number of lines, but all the callbacks are gone. This makes it way
90
+
easier to read, especially for those less familiar with promises.
79
91
80
92
## Other async function syntax
81
93
82
-
We've seen `async function() {}` already, but the `async` keyword can be used with other function syntax:
94
+
We've seen `async function() {}` already, but the `async` keyword can be used
95
+
with other function syntax:
83
96
84
97
### Arrow functions
85
98
@@ -89,7 +102,9 @@ We've seen `async function() {}` already, but the `async` keyword can be used wi
89
102
return response.json();
90
103
});
91
104
92
-
Note: `array.map(func)` doesn't care that I gave it an async function, it just sees it as a function that returns a promise. It won't wait for the first function to complete before calling the second.
105
+
Note: `array.map(func)` doesn't care that I gave it an async function, it just
106
+
sees it as a function that returns a promise. It won't wait for the first
107
+
function to complete before calling the second.
93
108
94
109
### Object methods
95
110
@@ -122,7 +137,8 @@ Note: Class constructors cannot be async.
122
137
123
138
## Example: Streaming a response
124
139
125
-
The benefit of async functions increases in more complex examples. Say we wanted to stream a response while logging out the chunks and returning the final size.
140
+
The benefit of async functions increases in more complex examples. Say we wanted
141
+
to stream a response while logging out the chunks and returning the final size.
126
142
127
143
Note: The phrase "logging out the chunks" made me sick in my mouth.
128
144
@@ -145,7 +161,11 @@ Here it is with promises:
145
161
});
146
162
}
147
163
148
-
Check me out, Jake "wielder of promises" Archibald. See how I'm calling `processResult` inside itself to set up an asynchronous loop? Writing that made me feel *very smart*. But like most "smart" code, you have to stare at it for ages to figure out what it's doing, like one of those magic-eye pictures from the 90's.
164
+
Check me out, Jake "wielder of promises" Archibald. See how I'm calling
165
+
`processResult` inside itself to set up an asynchronous loop? Writing that made
166
+
me feel *very smart*. But like most "smart" code, you have to stare at it for
167
+
ages to figure out what it's doing, like one of those magic-eye pictures from
168
+
the 90's.
149
169
150
170
Let's try that again with async functions:
151
171
@@ -164,13 +184,22 @@ Let's try that again with async functions:
164
184
return total;
165
185
}
166
186
167
-
All the "smart" is gone. The asynchronous loop that made me feel so smug is replaced with a trusty, boring, while-loop. Much better. In future, we'll get [async iterators](https://github.com/tc39/proposal-async-iteration){: .external}, which would [replace the above `while` loop](https://gist.github.com/jakearchibald/0b37865637daf884943cf88c2cba1376){: .external}.
187
+
All the "smart" is gone. The asynchronous loop that made me feel so smug is
188
+
replaced with a trusty, boring, while-loop. Much better. In future, we'll get
Note: I'm sort-of in love with streams. If you're unfamiliar with streaming, [check out my guide](https://jakearchibald.com/2016/streams-ftw/#streams-the-fetch-api){: .external}.
194
+
Note: I'm sort-of in love with streams. If you're unfamiliar with streaming,
Say we wanted to fetch a series URLs and log them as soon as possible, in the correct order.
201
+
Say we wanted to fetch a series URLs and log them as soon as possible, in the
202
+
correct order.
174
203
175
204
*Deep breath* - here's how that looks with promises:
176
205
@@ -187,9 +216,11 @@ Say we wanted to fetch a series URLs and log them as soon as possible, in the co
187
216
}, Promise.resolve());
188
217
}
189
218
190
-
Yeah, that's right, I'm using `reduce` to chain a sequence of promises. I'm *so smart*. But this is a bit of *so smart* coding we're better off without.
219
+
Yeah, that's right, I'm using `reduce` to chain a sequence of promises. I'm *so
220
+
smart*. But this is a bit of *so smart* coding we're better off without.
191
221
192
-
However, when converting the above to an async function, it's tempting to go *too sequential*:
222
+
However, when converting the above to an async function, it's tempting to go
223
+
*too sequential*:
193
224
194
225
<spanclass="compare-worse">Not recommended</span> - too sequential
195
226
@@ -200,7 +231,9 @@ However, when converting the above to an async function, it's tempting to go *to
200
231
}
201
232
}
202
233
203
-
Looks much neater, but my second fetch doesn't begin until my first fetch has been fully read, and so on. This is much slower than the promises example that performs the fetches in parallel. Thankfully there's an ideal middle-ground:
234
+
Looks much neater, but my second fetch doesn't begin until my first fetch has
235
+
been fully read, and so on. This is much slower than the promises example that
236
+
performs the fetches in parallel. Thankfully there's an ideal middle-ground:
204
237
205
238
<spanclass="compare-better">Recommended</span> - nice and parallel
206
239
@@ -217,42 +250,62 @@ Looks much neater, but my second fetch doesn't begin until my first fetch has be
217
250
}
218
251
}
219
252
220
-
In this example, the URLs are fetched and read in parallel, but the "smart" `reduce` bit is replaced with a standard, boring, readable for-loop.
253
+
In this example, the URLs are fetched and read in parallel, but the "smart"
254
+
`reduce` bit is replaced with a standard, boring, readable for-loop.
221
255
222
256
## Browser support & workarounds
223
257
224
-
At time of writing, async functions are enabled by default in Chrome 55, but they're being developed in all the main browsers:
258
+
At time of writing, async functions are enabled by default in Chrome 55, but
259
+
they're being developed in all the main browsers:
225
260
226
261
* Edge - [In build 14342+ behind a flag](https://developer.microsoft.com/en-us/microsoft-edge/platform/status/asyncfunctions/)
If you're targeting browsers that support generators (which includes [the latest version of every major browser](http://kangax.github.io/compat-table/es6/#test-generators){: .external}) you can sort-of polyfill async functions.
267
+
If you're targeting browsers that support generators (which includes [the latest
.external}) you can sort-of polyfill async functions.
233
271
234
-
[Babel](https://babeljs.io/){: .external} will do this for you, [here's an example via the Babel REPL](https://goo.gl/0Cg1Sq){: .external} - note how similar the transpiled code is. This transformation is part of [Babel's stage 3 preset](http://babeljs.io/docs/plugins/preset-stage-3/){: .external}.
272
+
[Babel](https://babeljs.io/){: .external} will do this for you, [here's an
273
+
example via the Babel REPL](https://goo.gl/0Cg1Sq){: .external} - note how
274
+
similar the transpiled code is. This transformation is part of [Babel's stage 3
I recommend the transpiling approach, because you can just turn it off once your target browsers support async functions, but if you *really* don't want to use a transpiler, you can take [Babel's polyfill](https://gist.github.com/jakearchibald/edbc78f73f7df4f7f3182b3c7e522d25){: .external} and use it yourself. Instead of:
279
+
I recommend the transpiling approach, because you can just turn it off once your
280
+
target browsers support async functions, but if you *really* don't want to use a
Note that you have to pass a generator (`function*`) to `createAsyncFunction`, and use `yield` instead of `await`. Other than that it works the same.
299
+
Note that you have to pass a generator (`function*`) to `createAsyncFunction`,
300
+
and use `yield` instead of `await`. Other than that it works the same.
253
301
254
302
### Workaround - regenerator
255
303
256
-
If you're targeting older browsers, Babel can also transpile generators, allowing you to use async functions all the way down to IE8. To do this you need [Babel's stage 3 preset](http://babeljs.io/docs/plugins/preset-stage-3/){: .external} *and* the [ES2015 preset](http://babeljs.io/docs/plugins/preset-es2015/){: .external}.
304
+
If you're targeting older browsers, Babel can also transpile generators,
305
+
allowing you to use async functions all the way down to IE8. To do this you need
0 commit comments