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
+32-23Lines changed: 32 additions & 23 deletions
Original file line number
Diff line number
Diff line change
@@ -9,13 +9,13 @@ 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.
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.
13
13
14
14
Async functions look like this:
15
15
16
-
async function myFirstAsyncFucntion() {
16
+
async function myFirstAsyncFunction() {
17
17
try {
18
-
const resolvedValue = await aPromise;
18
+
const fulfilledValue = await promise;
19
19
}
20
20
catch (rejectedValue) {
21
21
// …
@@ -26,7 +26,7 @@ If you use the `async` keyword before a function definition, you can then use `a
26
26
27
27
Note: If you're unfamiliar with promises & promise terminology, check out [our promises guide](/web/fundamentals/getting-started/primers/promises).
28
28
29
-
Calling an async function returns a promise for whatever the function returns or throws. So:
29
+
Calling an async function returns a promise for whatever the function returns or throws. So with:
30
30
31
31
// wait ms milliseconds
32
32
function wait(ms) {
@@ -47,6 +47,8 @@ Calling an async function returns a promise for whatever the function returns or
47
47
48
48
…calling `foo()` returns a promise that *rejects* with `Error('bar')`.
49
49
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).
51
+
50
52
## Example: Logging a fetch
51
53
52
54
Say we wanted to fetch a URL and log the response as text. Here's how it looks using promises:
@@ -73,7 +75,7 @@ And here's the same thing using async functions:
73
75
}
74
76
}
75
77
76
-
It's the same number of lines, but all the callbacks are gone, making it way easier to read, especially for those less familiar with promises.
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.
77
79
78
80
## Other async function syntax
79
81
@@ -98,6 +100,8 @@ Note: `array.map(func)` doesn't care that I gave it an async function, it just s
98
100
}
99
101
};
100
102
103
+
storage.getAvatar('jaffathecake').then(…);
104
+
101
105
### Class methods
102
106
103
107
class Storage {
@@ -111,13 +115,16 @@ Note: `array.map(func)` doesn't care that I gave it an async function, it just s
111
115
}
112
116
}
113
117
118
+
const storage = new Storage();
119
+
storage.getAvatar('jaffathecake').then(…);
120
+
114
121
Note: Class constructors cannot be async.
115
122
116
123
## Example: Streaming a response
117
124
118
-
Note: If you're unfamiliar with streaming, [check out my guide](https://jakearchibald.com/2016/streams-ftw/#streams-the-fetch-api){: .external}.
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.
119
126
120
-
The benefit of async functions increases in more complex examples. Say we wanted to stream a response, logging out the chunks and returning the final size:
127
+
Note: The phrase "logging out the chunks" made me sick in my mouth.
121
128
122
129
Here it is with promises:
123
130
@@ -138,7 +145,7 @@ Here it is with promises:
138
145
});
139
146
}
140
147
141
-
Look at that! 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.
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.
142
149
143
150
Let's try that again with async functions:
144
151
@@ -157,33 +164,34 @@ Let's try that again with async functions:
157
164
return total;
158
165
}
159
166
160
-
The asynchronous loop that made me feel so smug is replaced with a trusty, boring, while-loop. Much better.
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}.
161
168
162
-
Note: The phrase "logging out the chunks" made me sick in my mouth.
169
+
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}.
163
170
164
-
## Example: Avoid going too linear
171
+
## Example: Avoid going too sequential
165
172
166
-
Ok, last example. Say we wanted to fetch a sequence of URLs and log them as soon as possible, in the correct order.
173
+
Say we wanted to fetch a series URLs and log them as soon as possible, in the correct order.
167
174
168
175
*Deep breath* - here's how that looks with promises:
Check me out, Jake "wielder of promises" Archibald, using `reduce` to process a sequence of promises. That's definitely a bit of *so smart* coding we'd be better off without.
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.
183
191
184
-
When converting the above to an async function, it's tempting to go *too linear*:
192
+
However, when converting the above to an async function, it's tempting to go *too sequential*:
185
193
186
-
<spanclass="compare-worse">Not recommended</span> - too linear
194
+
<spanclass="compare-worse">Not recommended</span> - too sequential
187
195
188
196
async function logInOrder(urls) {
189
197
for (const url of urls) {
@@ -197,18 +205,19 @@ Looks much neater, but my second fetch doesn't begin until my first fetch has be
197
205
<spanclass="compare-better">Recommended</span> - nice and parallel
198
206
199
207
async function logInOrder(urls) {
200
-
// go fetch
208
+
// fetch all the URLs in parallel
201
209
const textPromises = urls.map(async url => {
202
210
const response = await fetch(url);
203
211
return response.text();
204
212
});
205
213
214
+
// log them in sequence
206
215
for (const textPromise of textPromises) {
207
216
console.log(await textPromise);
208
217
}
209
218
}
210
219
211
-
In this example, the URLs are fetched and read as text in parallel, but the "smart" `reduce` bit is replaced with a standard, readable, for-loop.
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.
212
221
213
222
## Browser support & workarounds
214
223
@@ -222,28 +231,28 @@ At time of writing, async functions are enabled by default in Chrome 55, but the
222
231
223
232
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.
224
233
225
-
Babelwill do this for you, [here's an example via the Babel REPL](https://goo.gl/0Cg1Sq){: .external} - note how similar the transpiled code is.
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}.
226
235
227
236
Note: Babel REPL is fun to say. Try it.
228
237
229
-
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) and use it yourself. Instead of:
238
+
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:
230
239
231
240
async function slowEcho(val) {
232
241
await wait(1000);
233
242
return val;
234
243
}
235
244
236
-
…you'd write:
245
+
…you'd include [the polyfill](https://gist.github.com/jakearchibald/edbc78f73f7df4f7f3182b3c7e522d25){: .external} and write:
Note that you have to pass in a generator (`function*`) and use `yield` instead of `await`. Other than that it works the same.
252
+
Note that you have to pass a generator (`function*`) to `createAsyncFunction`, and use `yield` instead of `await`. Other than that it works the same.
244
253
245
254
### Workaround - regenerator
246
255
247
-
If you're targeting older browsers, Babel can also transpile generators, allowing you to use async functions all the way down to IE8.
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}.
248
257
249
258
The [output is not as pretty](https://goo.gl/jlXboV), so watch out for code-bloat.
0 commit comments