Home > Back-end >  Restart a generator by delegating to itself in the end
Restart a generator by delegating to itself in the end

Time:05-07

I am wondering about the drawbacks of restarting a generator by delegating to itself in the end.

 function* myGenerator(){
   yield "value1";
   yield "value2";
   yield "value3";
   yield "value4";
   yield* myGenerator();
 }

 const generate = myGenerator();

for (let i = 0; i<15; i  ){
  document.getElementById("output").innerHTML  = generate.next().value   "[" i  "]" "<br />";
}
<div id="output"></div>

One drawback that came up to my mind is the possibility of an infinite loop if it is used as an iterator. It can be bypassed with a counter, though.

function* myGenerator(c){
  let counter = c? c: 0;
  yield "value1";
  yield "value2";
  yield "value3";
  yield "value4";
  counter  ;
  if (counter < 3){
    yield* myGenerator(counter);
  }
}

const generate = myGenerator();

for (let val of generate){
  document.getElementById("output").innerHTML  = val  "<br />";
}
<div id="output"></div>

CodePudding user response:

The recursive calls will consume the call stack, and at every yield this stack must be saved and restored.

Your example is a case of tail recursion, so it is easy to rewrite as a loop:

function* myGenerator() {
  while (true) {
    yield "value1";
    yield "value2";
    yield "value3";
    yield "value4";
  }
}

const generate = myGenerator();

for (let i = 0; i < 15; i  ) {
  document.getElementById("output").innerHTML  = generate.next().value   "["   i   "]<br>";
}
<div id="output"></div>

As to avoiding that you try to consume an infinite series, you could use a generic function for that.

Unrelated, but I'd only assign once to innerHTML:

function* myGenerator() {
  while (true) {
    yield "value1";
    yield "value2";
    yield "value3";
    yield "value4";
  }
}

function* islice(iterator, count) {
  for (let value of iterator) {
    if (--count < 0) return;
    yield value;
  }
}

const generate = islice(myGenerator(), 15);

const values = Array.from(generate, (value, i) => value   "["   i   "]");
document.getElementById("output").innerHTML  = values.join("<br>");
<div id="output"></div>

CodePudding user response:

  1. Another case of inifity loop / Stackoverflow:
        function* myGenerator() {
            // when nothing to yield temply
            yield* myGenerator();
        }
  1. Bad for GC, too many instance created.
        var cur_counter = 0;
        function* myGenerator() {
            cur_counter  ;
            console.log("current count of generator: "   cur_counter);
            yield 1;
            yield* myGenerator();
            cur_counter--; // will never be called
        } 

EDIT

Callstack:

enter image description here

  • Related