Search code examples
typescriptrecursiongenerator

Maximum call stack size exceeded TypeScript Recursive Function returning a Generator returning a Promise


I have a generator that streams one line of a large file at a time. I only want to process one line at a time and the file size is likely to get quite large.

export async function *lineOfFileGenerator(fullFilePath: string) {
  const filestream = createReadStream(fullFilePath);
  const rl = createInterface({
    input: filestream,
    crlfDelay: Infinity
  });
  for await (const line of rl) {
    yield line;
  }
}

It is then instantiated

const gen = lineOfFileGenerator('./path/to/file')

I want to keep calling this generator (which returns a promise) until it is 'done'. Since it returns a promise, I can't loop and directly check if the done boolean is true. I made a recursive function

function genPrinter(geno: any): void | AsyncGeneratorFunction {
  geno.next().then((val: { done: boolean; value: string; }) => {
    if (val.done) {
      console.log('done');
      return;
    }
    // will eventually call a processing function.
    console.log(val.value);
  });
  return genPrinter(geno);
}

However, I get RangeError: Maximum call stack size exceeded.

I'm not sure of the best way to call this generator/solve this problem.


Solution

  • Recursive functions expect some condition to exit. In your case you called genPrinter endlessly, in this case you don't need a recursive function, just an await..for loop to do the work. Here I refactored your code a bit:

    async function genPrinter(geno: any) {
      for await (let val of geno) {
        console.log('value:', val);
      }
      console.log('done');
    }
    

    If you still want to do same thing, in your method try this:

    async function genPrinter(geno: any): void | AsyncGeneratorFunction {
      let { done, value } = await geno.next();
      if (done) {
          console.log('done');
          return;
      }
      console.log(value);
      return genPrinter(geno);
    }