Информация

Дата основания
Местоположение
Россия
Сайт
team.mail.ru
Численность
5 001–10 000 человек
Дата регистрации

Блог на Хабре

Обновить
Комментарии 12
Не хватает какого-то реального примера, а не сферического коня в вакууме. С сахаром или без, но за, почти 10 лет разработки, продуктовой, обычной и тп, ни разу подобное не пригодилось.

Ну, например, есть у меня двухссылочный список. Возможно — закольцованный. Мне нужно начиная с переданного элемента итерироваться по нему в заданную сторону, причём, условие завершения может быть разным.
Я пишу генератор, с простым условием завершения — пустая ссылка. Он потенциально бесконечный. А настоящим условием завершения ведает вызывающая функция, которая в некоторых случаях тоже может быть генератором.
Очень удобно.

Всё то же самое можно сделать с колбэком, в стиле forEach. Возврат, к примеру, значения false в колбэке — признак что пора закругляться. Если признак завершения определяется асинхронно, то в нашем списковом forEach можно предусмотреть возврат промиса и использовать async функцию. Вряд ли это будет сильно сложнее.

Можно, но это менее гибко. Я так сперва и сделал, но потом потребовалась различная обработка результатов и сложное условие завершения. Чтобы не усложнять логику обработки возврата из коллбека, я перешёл на генератор. Сложный метод распался на два простых.


Вряд ли это будет сильно сложнее.

Однозначно сложнее. Потому что проще чем генератор — уже некуда.

Пакет redux-saga(Weekly Downloads: 811 526). Очень приятная работа с генераторами, если TS, то есть typed-redux-saga. Постоянно использую в продакшене. Порог входа новых разрабов немного выше, но очень быстро окупается, тк код легче читается.

Есть ощущение, что в redux-saga 90% вещей можно было бы упростить, сменив интерфейс на async-await (или хотя бы сделав его async-совместимым). Т.е. генераторы там как бы слишком чрезмерно и широко используются. Интересно, это правда так?

Нет, это неправда. Саги оправданы если оправдано использование редакса, говорю в контексте реакта. Если не хватает возможностей контекста и нужен редакс, то на сагах можно линейно описать всю логику работы с данными. При этом все саги будут описывать работу какого-то функционала. Можно описать любой сценарий «человеческим языком». Конечно, все можно сделать множеством способов, но с сагой, если правильно готовить, будет выходить красиво. Да, тут напрашивается пример кода, но нет под рукой примера без НДА. Завтра немного адаптирую и скину.

Итерирование по узлам дерева обычным циклом, например.

Самый распространённый в моей практике случай: загрузка каких-либо данных (например постов блога) частями. Это СУПЕР удобно.
Пишешь асинхронный генератор, который хранит в себе данные для пагинации и загружает посты.
А дальше используешь


iterator.next(<post_per_page>)

чтобы загрузить новую партию постов.

Слушайте, итераторы и генераторы — это всего где-то 5% сложности. Статья из разряда “пишем hello world”. А остальные 95% сидят вот где:


  1. AsyncIterator
  2. AsyncIterable и AsyncGenerator
  3. Конкуретное выполнение next() в AsyncIterator (там вообще черт ногу сломит).
  4. Внешний вызов return() у AsyncIterator (или уже AsyncGenerator?) и его поведение при выбросе исключений.
  5. Конкурентный внешний вызов return() (черт сломает вторую ногу).
  6. Внешний вызов throw() у AsyncIterator (или AsyncGenerator все же?).
  7. TS-типы этих трех интерфейсов, их схожесть и различие.

На все это есть спека в Ecmascript (написанная на таком своеобразном птичьем псевдоязыке), но она такая громадная и непонятная, что черт сломит четвертую, пятую и все остальные ноги.

Еще одно. Поправьте меня если я ошибаюсь (и очень интересны мнения специалистов на эту тему в комментах тоже), но AsyncIterator/AsyncGenerator — это такой ответ JS на концепцию Observables, сделанный с тем расчетом, чтобы их упростить (потому что сами Observables — крайне сложная в освоении концепция для большинства инженеров). Такой своеобразный протест. В принципе, использовать AsyncGenerator и правда проще в подавляющем большинстве случаев, чем Observables. (Хотя они немного различаются: AsyncGenerator — это скорее pull, а Observable — это скорее push, но в реальной жизни возможны комбинации.)


Также это ответ на Streams и их крайнюю сложность в вопросах backpressure (а без обработки backpressure почти ничего серьезного, по сути, и не сделать). Такая отчаянная попытка починить все это, пока окончательно не схлопнулось под весом собственной сложности.

Генератор — это способ создавать итераторы. Везде, где удобно использовать some.next() — можно использовать генераторы/итераторы.

Вообще когда говорят о генераторах, забывают, что они сами по себе — просто сервисная штука для создания итераторов.

И вот когда вы привыкаете думать итераторами, все становится проще и появляется смысл.

Пример — небольшая игра, типа рогалик. Герой заходит в комнату. Как мы получаем рандомную комнату? Вот так

const room = roomBuilder.next();

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.