Pull to refresh

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.


Насколько я понимаю, код генератора можно выполнять как синхронно, так и асинхронно, это решает интегрирующий его код. Поправьте меня если я не прав

Спасибо, приятно слышать!
Да, взглядом со стороны я теперь понимаю, что не очень удачное слово выбрал.
Под тем, что генератор выполняется не синхронно, я имел в виду, что внутри генератора нету понимания, сколько времени пройдёт от начала кода до конца и будет ли этот код выполнен в рамках одного стека эвент лупа.

С такой формулировкой я полностью согласен, спасибо

Предлагаю читателю ответить на вопрос: является ли массив итератором?


Но ведь правильно звучит «я могу проитерировать массив», а не «я могу проитерировать итератор»?

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

Думаю, автор хотел сказать, что массив — это итеруруемый объект, а не итератор.


Массив итеруруемый объект потому, что он реализовывает "итератор протокол" внутри себя.


Навность же методов а map, делают его ещё Функтором, а flatMap, возможно Монадой, но это нужно доказывать

Ну так это совсем другое дело, тем более что массив в javascript это именно объект с готовыми методами для итерации.
Я придирался к формулировке.

Было бы неплохо потратить ещё одну статью на сравнение c# и его IEnumerable/IEnumerator: в общем-то тоже можно реализовать практически аналогичные вещи, даже без поддержки yield.


Просто пока не понимаю восторгов по поводу "киллерфичности" в javascript.

Насколько могу судить это примерно то же самое. Киллер фича заключается в том, что код генератора может не исполняться весь сразу, а останавливаться и возобновляться, при этом не теряя своего состояния.
посмотрите на yield в python, все очень похоже, это безусловно интересная фича, но точно не уникальная для js. В scala yield это вообще швейцарский нож монадических трансформаций, но это совсем другая история.
не понимаю восторгов по поводу "киллерфичности" в javascript.

А вы попишите на javascript без генераторов, а потом перейдите генераторы. Сразу поймёте.
Какая нахрен "киллерфичность"? Мы радуемся, что язык становится лучше!


Сравнение с другими языками — не в тему, до тех пор, пока оные не будут поддерживаться браузерами.

Давно пописываю на JS. Пробовал генераторы, но как-то не особо нашёл полезных применений кроме как ьранспилить async/await. Да, сейчас в основном mobx+React, mst не зашёл…

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

Ну вот для задачи "обойти возможно закольцованный список" генераторы вроде подходят, но вот подобных задач как-то не попадалось

Одно из отличий в том, что в js генератор может получать значения.
Например:
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# так нельзя.

Что из этого нельзя было прочитать на Мозилле?

Sign up to leave a comment.

Articles