Comments 21
Хотелось бы ещё конкретных примеров их применения. А то я в который раз понял, как они работают, но когда придумываю какой-то алгоритм, то не применяю их, потому что у меня в голове нет шаблона их применения.
Всё же, не часто приходится пользоваться числами Фибоначчи.
Согласен, на это хочу ещё одну статью потратить. А пока можно посмотреть на redux-saga, js-csp
Мне кажется, что одно из интересных применение генераторов — проход дерева
function* dfs (root) {
yield root;
for (const child of root.children)
yield* dfs(child);
}
И теперь если внутри какой нибудь логики нам нужно получить все ноды, постепенно уходя в глубину, то можно легко обойтись обычным циклом по генератору:
for (let node of dfs(obj)) {
console.log(node)
}
Так же генераторы используют для контроля состояния (тот же redux-saga)
Я бы добавил, что с помощью протокола Iterable можно ещё слаще сделать реализацию:
class Node {
constructor(data) {
this.data = data;
this.children = [];
}
add (node) {
this.children.push(node);
}
[Symbol.iterator] = function* () {
yield this.data;
for (const child of this.children) {
yield* child;
}
}
}
const root = new Node(1);
root.add(new Node('kek'));
root.add(new Node('pipi'));
root.add(new Node(1));
console.log(Array.from(root)); // [ 1, 'kek', 'pipi', 1 ]
console.log(new Set(root)) // Set { 1, 'kek', 'pipi' }
Спасибо за статью, вы очень просто объяснили. Буду ждать следующую статью :)
Единственное что меня на время запутало, это фраза: "код внутри генератора выполняется не синхронно". Это звучит так, будьто генераторы всегда выполняются асинхронно, но ведь код примера выполнения синхронно так как не проходит через event loop.
Насколько я понимаю, код генератора можно выполнять как синхронно, так и асинхронно, это решает интегрирующий его код. Поправьте меня если я не прав
Спасибо, приятно слышать!
Да, взглядом со стороны я теперь понимаю, что не очень удачное слово выбрал.
Под тем, что генератор выполняется не синхронно, я имел в виду, что внутри генератора нету понимания, сколько времени пройдёт от начала кода до конца и будет ли этот код выполнен в рамках одного стека эвент лупа.
Мимо
Предлагаю читателю ответить на вопрос: является ли массив итератором?
Но ведь правильно звучит «я могу проитерировать массив», а не «я могу проитерировать итератор»?
Не во всех языках массив — это класс со встроенными методами.
И опять таки, в массиве есть и другие методы, не все их них можно использовать для итерирования.
Можете пояснить свою фразу, почему массив — это итератор?
Думаю, автор хотел сказать, что массив — это итеруруемый объект, а не итератор.
Массив итеруруемый объект потому, что он реализовывает "итератор протокол" внутри себя.
Навность же методов а map, делают его ещё Функтором, а flatMap, возможно Монадой, но это нужно доказывать
Было бы неплохо потратить ещё одну статью на сравнение c# и его IEnumerable/IEnumerator: в общем-то тоже можно реализовать практически аналогичные вещи, даже без поддержки yield.
Просто пока не понимаю восторгов по поводу "киллерфичности" в javascript.
не понимаю восторгов по поводу "киллерфичности" в javascript.
А вы попишите на javascript без генераторов, а потом перейдите генераторы. Сразу поймёте.
Какая нахрен "киллерфичность"? Мы радуемся, что язык становится лучше!
Сравнение с другими языками — не в тему, до тех пор, пока оные не будут поддерживаться браузерами.
Давно пописываю на JS. Пробовал генераторы, но как-то не особо нашёл полезных применений кроме как ьранспилить async/await. Да, сейчас в основном mobx+React, mst не зашёл…
Странно. А я их использую не то, чтобы широко, но довольно регулярно.
Ну, допустим, из недавнего, у меня есть двухуказательный список и элемент начала обхода. Этот список может внезапно оказаться закольцован — я заранее этого не знаю.
Я написал генератор, который обходит этот список в выбранном направлении. Возможно этот генератор никогда не закончит работу — ну и бог бы с ним, никто и не просит читать его весь.
Другой генератор читает первый и возвращает его элементы до тех пор, пока не дочитает до конца или не вернётся к началу.
В результате вместо одной сложной процедуры — две простые. Причём, первую из них можно использовать и отдельно.
Например:
function* g(max) {
let n = 1;
while (n < max) n = (yield n++) ?? n;
}
let i = g(100);
i.next().value // 1
i.next().value // 2
i.next().value // 3
i.next(1).value // 1
i.next().value // 2
i.next().value // 3
В C# так нельзя.
Что из этого нельзя было прочитать на Мозилле?
Эффектное программирование. Часть 1: итераторы и генераторы