Skip to content

Commit 58f6599

Browse files
committed
minor fixes
1 parent a9c170a commit 58f6599

File tree

1 file changed

+41
-31
lines changed
  • 1-js/12-generators-iterators/2-async-iterators-generators

1 file changed

+41
-31
lines changed

Diff for: 1-js/12-generators-iterators/2-async-iterators-generators/article.md

+41-31
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11

2-
# Async iterators and generators
2+
# Async iteration and generators
33

4-
Asynchronous iterators allow us to iterate over data that comes asynchronously, on-demand. Like, for instance, when we download something chunk-by-chunk over a network. And asynchronous generators make it even more convenient.
4+
Asynchronous iteration allow us to iterate over data that comes asynchronously, on-demand. Like, for instance, when we download something chunk-by-chunk over a network. And asynchronous generators make it even more convenient.
55

66
Let's see a simple example first, to grasp the syntax, and then review a real-life use case.
77

8-
## Recall iterators
8+
## Recall iterables
99

10-
Let's recall the topic about iterators.
10+
Let's recall the topic about iterables.
1111

1212
The idea is that we have an object, such as `range` here:
1313
```js
@@ -17,17 +17,17 @@ let range = {
1717
};
1818
```
1919

20-
...And we'd like to use `for..of` loop on it, such as `for(value of range)`, to get values from `1` to `5`. And otherwise use the object, as if it were an array.
20+
...And we'd like to use `for..of` loop on it, such as `for(value of range)`, to get values from `1` to `5`.
2121

2222
In other words, we want to add an *iteration ability* to the object.
2323

2424
That can be implemented using a special method with the name `Symbol.iterator`:
2525

26-
- This method is called in the beginning of a `for..of` loop, and it should return an object with the `next` method.
27-
- For each iteration of `for..of`, the `next()` method is invoked for the next value.
28-
- The `next()` should return a value in the form `{done: true/false, value:<loop value>}`.
26+
- This method is called in by the `for..of` construct when the loop is started, and it should return an object with the `next` method.
27+
- For each iteration, the `next()` method is invoked for the next value.
28+
- The `next()` should return a value in the form `{done: true/false, value:<loop value>}`, where `done:true` means the end of the loop.
2929

30-
Here's an implementation for the `range`, with all the comments:
30+
Here's an implementation for the iterable `range`:
3131

3232
```js run
3333
let range = {
@@ -59,19 +59,17 @@ for(let value of range) {
5959
}
6060
```
6161

62-
If anything is unclear, please visit the [chapter about iterables](info:iterable), it gives all the details about regular iterators.
62+
If anything is unclear, please visit the chapter [](info:iterable), it gives all the details about regular iterables.
6363

64-
## Async iterators
64+
## Async iterables
6565

66-
Asynchronous iterators are similar to regular iterators. We also need to have an iterable object, but values are expected to come asynchronously.
66+
Asynchronous iteration is needed when values come asynchronously: after `setTimeout` or another kind of delay.
6767

68-
The most common case is that the object needs to make a network request to deliver the next value.
68+
The most common case is that the object needs to make a network request to deliver the next value, we'll see a real-life example of it a bit later.
6969

70-
Regular iterators, as the one above, require `next()` to return the next value right away. That's where asynchronous iterators come into play.
70+
To make an object iterable asynchronously:
7171

72-
To make the object iterable asynchronously:
73-
74-
1. We need to use `Symbol.asyncIterator` instead of `Symbol.iterator`.
72+
1. Use `Symbol.asyncIterator` instead of `Symbol.iterator`.
7573
2. The `next()` method should return a promise (to be fulfilled with the next value).
7674
- The `async` keyword handles it, we can simply make `async next()`.
7775
3. To iterate over such an object, we should use a `for await (let item of iterable)` loop.
@@ -153,9 +151,9 @@ It's also the case for `for..of`: the syntax without `await` needs `Symbol.itera
153151
154152
## Recall generators
155153
156-
Now let's recall generators. They are explained in detail in the chapter [](info:generators).
154+
Now let's recall generators, as they allow to make iteration code much shorter. Most of the time, when we'd like to make an iterable, we'll use generators.
157155
158-
For sheer simplicity, omitting some important stuff, they are "functions that generate (yield) values".
156+
For sheer simplicity, omitting some important stuff, they are "functions that generate (yield) values". They are explained in detail in the chapter [](info:generators).
159157
160158
Generators are labelled with `function*` (note the start) and use `yield` to generate a value, then we can use `for..of` to loop over them.
161159
@@ -187,7 +185,7 @@ let range = {
187185
}
188186
```
189187
190-
A common practice for `Symbol.iterator` is to return a generator, it makes the code shorter:
188+
A common practice for `Symbol.iterator` is to return a generator, it makes the code shorter, as you can see:
191189
192190
```js run
193191
let range = {
@@ -208,15 +206,19 @@ for(let value of range) {
208206
209207
Please see the chapter [](info:generators) if you'd like more details.
210208
211-
Once again, what if we'd like to generate values asynchronously? From network requests, for instance.
212-
213209
In regular generators we can't use `await`. All values must come synchronously, as required by the `for..of` construct.
214210
215-
Let's switch to asynchronous generators, to make it possible.
211+
What if we'd like to generate values asynchronously? From network requests, for instance.
212+
213+
Let's switch to asynchronous generators to make it possible.
216214
217-
## Async generators
215+
## Async generators (finally)
218216
219-
To make an asynchronous generator, prepend `function*` with `async`, like this:
217+
For most practical applications, when we'd like to make an object that asynchronously generates a sequence of values, we can use an asynchronous generator.
218+
219+
The syntax is simple: prepend `function*` with `async`. That makes the generator asynchronous.
220+
221+
And then use `for await (...)` to iterate over it, like this:
220222
221223
```js run
222224
*!*async*/!* function* generateSequence(start, end) {
@@ -237,15 +239,13 @@ To make an asynchronous generator, prepend `function*` with `async`, like this:
237239
238240
let generator = generateSequence(1, 5);
239241
for *!*await*/!* (let value of generator) {
240-
alert(value); // 1, then 2, then 3, then 4, then 5
242+
alert(value); // 1, then 2, then 3, then 4, then 5 (with delay between)
241243
}
242244
243245
})();
244246
```
245247
246-
Now we have the async generator, iterable with `for await...of`.
247-
248-
It's really simple. We add the `async` keyword, and the generator now can use `await` inside of it, rely on promises and other async functions.
248+
As the generator is asynchronous, we can use `await` inside it, rely on promises, perform network requests and so on.
249249
250250
````smart header="Under-the-hood difference"
251251
Technically, if you're an advanced reader who remembers the details about generators, there's an internal difference.
@@ -260,7 +260,13 @@ result = await generator.next(); // result = {value: ..., done: true/false}
260260
That's why async generators work with `for await...of`.
261261
````
262262

263-
We can make the `range` object generate values asynchronously, once per second, by replacing synchronous `Symbol.iterator` with asynchronous `Symbol.asyncIterator`:
263+
### Async iterable range
264+
265+
Regular generators can be used as `Symbol.iterator` to make the iteration code shorter.
266+
267+
Similar to that, async generators can be used as `Symbol.asyncIterator` to implement the asynchronous iteration.
268+
269+
For instance, we can make the `range` object generate values asynchronously, once per second, by replacing synchronous `Symbol.iterator` with asynchronous `Symbol.asyncIterator`:
264270

265271
```js run
266272
let range = {
@@ -292,7 +298,11 @@ let range = {
292298

293299
Now values come with a delay of 1 second between them.
294300

295-
So, we can make any object asynchronously iterable by adding an async generator as its `Symbol.asyncIterator` method, and letting it to generate values.
301+
```smart
302+
Technically, we can add both `Symbol.iterator` and `Symbol.asyncIterator` to the object, so it's both synchronously (`for..of`) and asynchronously (`for await..of`) iterable.
303+
304+
In practice though, that would be an weird thing to do.
305+
```
296306

297307
## Real-life example: paginated data
298308

0 commit comments

Comments
 (0)