Skip to content
This repository was archived by the owner on Aug 10, 2022. It is now read-only.

Commit 7432545

Browse files
committed
Second draft
1 parent 9c44b0c commit 7432545

File tree

1 file changed

+32
-23
lines changed

1 file changed

+32
-23
lines changed

src/content/en/fundamentals/getting-started/primers/async-functions.md

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ description: TODO
99

1010
{% include "web/_shared/contributors/jakearchibald.html" %}
1111

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.
1313

1414
Async functions look like this:
1515

16-
async function myFirstAsyncFucntion() {
16+
async function myFirstAsyncFunction() {
1717
try {
18-
const resolvedValue = await aPromise;
18+
const fulfilledValue = await promise;
1919
}
2020
catch (rejectedValue) {
2121
// …
@@ -26,7 +26,7 @@ If you use the `async` keyword before a function definition, you can then use `a
2626

2727
Note: If you're unfamiliar with promises & promise terminology, check out [our promises guide](/web/fundamentals/getting-started/primers/promises).
2828

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:
3030

3131
// wait ms milliseconds
3232
function wait(ms) {
@@ -47,6 +47,8 @@ Calling an async function returns a promise for whatever the function returns or
4747

4848
…calling `foo()` returns a promise that *rejects* with `Error('bar')`.
4949

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+
5052
## Example: Logging a fetch
5153

5254
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:
7375
}
7476
}
7577

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.
7779

7880
## Other async function syntax
7981

@@ -98,6 +100,8 @@ Note: `array.map(func)` doesn't care that I gave it an async function, it just s
98100
}
99101
};
100102

103+
storage.getAvatar('jaffathecake').then(…);
104+
101105
### Class methods
102106

103107
class Storage {
@@ -111,13 +115,16 @@ Note: `array.map(func)` doesn't care that I gave it an async function, it just s
111115
}
112116
}
113117

118+
const storage = new Storage();
119+
storage.getAvatar('jaffathecake').then(…);
120+
114121
Note: Class constructors cannot be async.
115122

116123
## Example: Streaming a response
117124

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.
119126

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.
121128

122129
Here it is with promises:
123130

@@ -138,7 +145,7 @@ Here it is with promises:
138145
});
139146
}
140147

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.
142149

143150
Let's try that again with async functions:
144151

@@ -157,33 +164,34 @@ Let's try that again with async functions:
157164
return total;
158165
}
159166

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}.
161168

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}.
163170

164-
## Example: Avoid going too linear
171+
## Example: Avoid going too sequential
165172

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.
167174

168175
*Deep breath* - here's how that looks with promises:
169176

170177
function logInOrder(urls) {
171-
// go fetch
178+
// fetch all the URLs
172179
const textPromises = urls.map(url => {
173180
return fetch(url).then(response => response.text());
174181
});
175182

183+
// log them in order
176184
textPromises.reduce((chain, textPromise) => {
177185
return chain.then(() => textPromise)
178186
.then(text => console.log(text));
179187
}, Promise.resolve());
180188
}
181189

182-
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.
183191

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*:
185193

186-
<span class="compare-worse">Not recommended</span> - too linear
194+
<span class="compare-worse">Not recommended</span> - too sequential
187195

188196
async function logInOrder(urls) {
189197
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
197205
<span class="compare-better">Recommended</span> - nice and parallel
198206

199207
async function logInOrder(urls) {
200-
// go fetch
208+
// fetch all the URLs in parallel
201209
const textPromises = urls.map(async url => {
202210
const response = await fetch(url);
203211
return response.text();
204212
});
205213

214+
// log them in sequence
206215
for (const textPromise of textPromises) {
207216
console.log(await textPromise);
208217
}
209218
}
210219

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.
212221

213222
## Browser support & workarounds
214223

@@ -222,28 +231,28 @@ At time of writing, async functions are enabled by default in Chrome 55, but the
222231

223232
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.
224233

225-
Babel 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.
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}.
226235

227236
Note: Babel REPL is fun to say. Try it.
228237

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:
230239

231240
async function slowEcho(val) {
232241
await wait(1000);
233242
return val;
234243
}
235244

236-
…you'd write:
245+
…you'd include [the polyfill](https://gist.github.com/jakearchibald/edbc78f73f7df4f7f3182b3c7e522d25){: .external} and write:
237246

238247
const slowEcho = createAsyncFunction(function*(val) {
239248
yield wait(1000);
240249
return val;
241250
});
242251

243-
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.
244253

245254
### Workaround - regenerator
246255

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}.
248257

249258
The [output is not as pretty](https://goo.gl/jlXboV), so watch out for code-bloat.

0 commit comments

Comments
 (0)