Skip to content

Commit 4de55f5

Browse files
committed
es6
1 parent 2a0e215 commit 4de55f5

2 files changed

Lines changed: 106 additions & 11 deletions

File tree

1-js/10-es-modern/10-set-map/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ for(let entry of recipeMap) { // то же что и recipeMap.entries()
133133
Перебор осуществляется в порядке вставки. Объекты `Map` гарантируют это, в отличие от обычных объектов `Object`.
134134
[/smart]
135135

136-
Кроме того, у `Map` есть стандартный методы `forEach`, аналогичный массиву:
136+
Кроме того, у `Map` есть стандартный метод `forEach`, аналогичный массиву:
137137

138138
```js
139139
//+ run

1-js/10-es-modern/17-generator/article.md

Lines changed: 105 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,24 @@ alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*}
8080

8181
"Открутить назад" завершившийся генератор нельзя, но можно создать новый ещё одним вызовом `generateSequence()` и выполнить его.
8282

83+
[smart header="`function* (…)` или `function *(…)`?"]
84+
Технически можно ставить звёздочку как сразу после `function`, так и позже, перед названием. В интернет можно найти обе эти формы записи, они верны:
85+
```js
86+
function* f() {
87+
// звёздочка после function
88+
}
89+
90+
function *f() {
91+
// звёздочка перед названием
92+
}
93+
```
94+
95+
Автор этого текста полагает, что правильнее использовать первый вариант `function*`, так как звёздочка относится к типу объявляемой сущности (`function*` -- "функция-генератор"), а не к её названию. Конечно, это всего лишь рекомендация-мнение, не обязательное к выполнению, работать будет и так и эдак.
96+
[/smart]
97+
98+
99+
100+
83101
## Генератор -- итератор
84102

85103
Как вы, наверно, уже догадались по наличию метода `next()`, генератор является итерируемым объектом.
@@ -595,35 +613,112 @@ co(function*() {
595613
});
596614
```
597615

598-
**Библиотеку `co` можно использовать один раз в самом внешнем вызове.**
616+
Библиотека `co` обрабатывает результаты рекурсивно. То есть, если в результате `yield` получается генератор, то он тоже выполняется библиотекой `co`, и так далее.
599617

600-
Библиотека `co` обрабатывает результаты рекурсивно. То есть, если в результате `yield` получается генератор, то ...
618+
Звучит это сложнее, чем на самом деле. Практическое следствие простое -- мы можем использовать `yield` во вложенных вызовах функций.
601619

602-
TODO
620+
Например:
621+
622+
```js
623+
//+ run
624+
'use strict';
625+
626+
function* gen() {
627+
return yield gen2();
628+
}
629+
630+
function* gen2() {
631+
let result = yield new Promise(
632+
resolve => setTimeout(resolve, 1000, 'hello')
633+
);
634+
return result;
635+
}
636+
637+
co(function*() {
638+
let result = yield gen();
639+
alert(result); // hello
640+
});
641+
```
642+
643+
В примере выше: первый `yield` возвращет генератор `gen()`, при его выполнении `yield'ится` генератор `gen2()`, внутри которого `yield'ится` промис, который завершается с `"hello"`.
644+
645+
Библиотека `co` при этом -- только на самом верхнем уровне.
646+
647+
Пример `showUserAvatar()` можно переписать с использованием `co` вот так:
648+
649+
```js
650+
//+ run
651+
'use strict';
603652

653+
// Загрузить данные пользователя с нашего сервера
654+
function* fetchUser(url) {
655+
let userFetch = yield fetch(url);
656+
657+
let user = yield userFetch.json();
658+
659+
return user;
660+
}
661+
662+
// Загрузить профиль пользователя с github
663+
function* fetchGithubUser(user) {
664+
let githubFetch = yield fetch(`https://api.github.com/users/${user.name}`);
665+
let githubUser = yield githubFetch.json();
666+
667+
return githubUser;
668+
}
669+
670+
// Подождать ms миллисекунд
671+
function sleep(ms) {
672+
return new Promise(resolve => setTimeout(resolve, ms));
673+
}
674+
675+
// Использовать функции выше для получения аватара пользователя
676+
function* fetchAvatar(url) {
604677

678+
let user = yield* fetchUser(url);
679+
680+
let githubUser = yield* fetchGithubUser(user);
681+
682+
return githubUser.avatar_url;
683+
}
684+
685+
// Использовать функции выше для получения и показа аватара
605686
function* showUserAvatar() {
606687

607-
let userFetch = yield fetch('/article/generator/user.json');
608-
let userInfo = yield userFetch.json();
688+
let avatarUrl;
609689

610-
let githubFetch = yield fetch(`https://api.github.com/users/${userInfo.name}`);
611-
let githubUserInfo = yield githubFetch.json();
690+
*!*
691+
try {
692+
avatarUrl = yield* fetchAvatar('/article/generator/user.json');
693+
} catch(e) {
694+
avatarUrl = '/article/generator/anon.png';
695+
}
696+
*/!*
612697

613698
let img = new Image();
614-
img.src = githubUserInfo.avatar_url;
699+
img.src = avatarUrl;
615700
img.className = "promise-avatar-example";
616701
document.body.appendChild(img);
617702

618-
yield new Promise(resolve => setTimeout(resolve, 3000));
703+
yield sleep(2000);
619704

620705
img.remove();
621706

622707
return img.src;
623708
}
624709

710+
co(showUserAvatar);
711+
```
712+
713+
Заметим, что для перехвата ошибок при получении аватара используется `try..catch` вокруг `yield* fetchAvatar`. Несмотря на то, что операции -- асинхронные, мы можем использовать обычный `try..catch`. И это очень удобно!
714+
715+
TODO
716+
717+
718+
719+
720+
625721

626-
co(showUserAvatar)
627722

628723
[head]
629724
<style>

0 commit comments

Comments
 (0)